1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sstream>
#include <boost/thread.hpp>
// Simulation du traitement d'un algorithme sur deux unités
bool Algo(int i, int j, boost::mutex& coutMutex)
{
int iMs = (rand() % 10 + 1) * 1000;
coutMutex.lock();
std::cout << "Thread " << boost::this_thread::get_id() << " - Computing " << i << " and " << j << " for " << iMs << " ms" << std::endl;
coutMutex.unlock();
boost::this_thread::sleep_for(boost::chrono::milliseconds(iMs)); // Attendre entre 1 et 10 secondes
return iMs < 8000; // Dans 20% des cas l'algo indique qu'il n'a pas trouvé de meilleure solution
}
// Classe ce coordination des threads
class CExecute
{
public:
CExecute(int iNumber)
: m_iN(iNumber)
{
// m_pUsed est une liste de flags indiquant si l'unité I est en cours d'utilisation (via m_pUsed[I])
m_pUsed = new bool[m_iN];
for (int i = 0; i < m_iN; ++i)
m_pUsed[i] = false;
// m_pChanged indique si des changements ont été opérés sur l'unité I (via m_pChanged[I])
// En effet, si l'algo n'a rien amélioré depuis la dernière fois pour ces deux unités, inutile de le relancer
m_pChanged = new bool[m_iN];
for (int i = 0; i < m_iN; ++i)
m_pChanged[i] = true;
// Calculs du nombre de thread à utiliser, il est équivalent au maximum de couple (i, j) pouvant tourner en même temps sans incompatibilité
m_iNbThreads = (iNumber * (iNumber - 1)) / 6;
}
// Destructeur -> nettoyage
~CExecute()
{
delete m_pUsed;
delete m_pChanged;
}
// Donne un couple (i, j) "libre". Renvoi 0 s'il n'y en a pas, 1 s'il y en a et 2 s'il n'y a plus aucune opération à effectuer sur les unités
int GetNext(int& i, int&j)
{
boost::mutex::scoped_lock lock(m_mutex);
bool b = false; bool bContinue = false;
for (int p = 0; p < m_iN; ++p)
{
bContinue |= (m_pUsed[p] || m_pChanged[p]);
if (!m_pUsed[p] && (m_pChanged[p] || b)) // i et j doivent être libres, et i ou j doivent avoir changés depuis la dernière exécution du couple
{
if (!b) { i = p; b = true; }
else {
j = p;
m_pUsed[i] = true;
m_pUsed[j] = true;
return 1;
}
}
}
if (!bContinue)
return 2;
return 0;
}
// Démarrage d'un thread
void LaunchThread()
{
unsigned int lId = 0;
std::stringstream ss; ss << boost::this_thread::get_id(); ss >> lId;
srand(lId);
while (true)
{
int i; int j; int iRet = 0;
while (!(iRet = GetNext(i, j))) // On attend une dispo
{
}
if (iRet == 1) // S'il y en a une on applique l'algorithme
{
bool retAlgo = Algo(i, j, m_CoutMutex);
m_pChanged[i] = retAlgo;
m_pChanged[j] = retAlgo;
m_pUsed[i] = false;
m_pUsed[j] = false;
}
if (iRet == 2) // S'il n'y en a plus on stoppe le thread
{
m_CoutMutex.lock();
std::cout << "Thread " << boost::this_thread::get_id() << " - Finished !" << std::endl;
m_CoutMutex.unlock();
return;
}
}
}
// Lancement des threads
void Launch()
{
std::vector<boost::thread*> vecTh;
for (int i = 0; i < m_iNbThreads; ++i)
vecTh.push_back(new boost::thread(&CExecute::LaunchThread, this));
for (int i = 0; i < m_iNbThreads; ++i)
vecTh[i]->join();
for (int i = 0; i < m_iNbThreads; ++i)
delete vecTh[i];
}
private:
int m_iN;
bool* m_pUsed;
bool* m_pChanged;
int m_iNbThreads;
boost::mutex m_mutex;
boost::mutex m_CoutMutex;
};
int main(int argc, char *argv[])
{
CExecute exec(16);
exec.Launch();
} |
Partager