/**
* @file Concurrence.cxx
*
* @author D. Mathieu
* M. Laporte
*
* @date 17/02/2010
*
* @brief Concurrence
*
* Acces protege par une section critique implementee par un lock_guard
*
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
using namespace std;
using namespace boost;
enum { KErrArg = 253 }; // Erreur d'arguments de main()
typedef unsigned long long ULL_t;
typedef long long LL_t;
namespace
{
volatile LL_t a (0);
ULL_t NbBoucles;
mutex Mtx;
class Incr
{
public :
void operator () (void)
{
for (ULL_t i = 0; i < NbBoucles; ++i)
{
lock_guard <mutex> Lock (Mtx);
++a;
}
} // operator()()
}; // Incr
class Decr
{
public :
void operator () (void)
{
for (ULL_t i = 0; i < NbBoucles; ++i)
{
lock_guard <mutex> Lock (Mtx);
--a;
}
} // operator()()
}; // Decr
} // namespace anonyme
int main (int argc, char * argv [])
{
if (argc != 3)
{
cerr << "Usage : Concurrence <NbThreads> <NbBoucles>\n";
return KErrArg;
}
unsigned NbThreads;
{
istringstream is (argv [1]);
is >> NbThreads;
}
{
istringstream is (argv [2]);
is >> NbBoucles;
}
cout << "Nbre de threads : " << NbThreads
<< "\nNbre de boucles : " << NbBoucles << '\n';
// vector <thread *> VThreads;
thread_group threadGroup;
for (unsigned i = NbThreads; i--; )
{
// VThreads.push_back (new thread (Incr));
threadGroup.add_thread (new thread (Incr ()));
// VThreads.push_back (new thread (Decr));
threadGroup.add_thread (new thread (Decr ()));
}
// for (unsigned i = NbThreads * 2; i--; ) VThreads[i]->join ();
threadGroup.join_all ();
cout << "a = " << a << '\n';
return 0;
} // main()
Archives du 14 mars 2019
M4104C-boost-Exo2-Corrigé
/**
*
* @file SleepChronogram.h
*
* @author M. Laporte, D. Mathieu
*
* @date 05/01/2007
*
* @version 2.0
*
* @brief SleepChronogr() affiche periodiquement un caractere
**/
#if !defined __SLEEP_CHRONOGR_H__
#define __SLEEP_CHRONOGR_H__
#include <iostream> // ios_base::failure
#include <string>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
namespace nsUtil
{
// L'injection de la NTCTS
//
//=========================//
// //
extern std::string clrscr; //
// //
//=========================//
//
// vide l'ecran et positionne le curseur en haut a gauche
// La
//
//============//
// //
class gotoxy; //
// //
//============//
//
// est un injecteur qui positionne le curseur a l'ecran
// en position x et y :
//
// cout << gotoxy (10, 20) << ...
class gotoxy
{
public :
gotoxy (int x, int y);
friend std::ostream & operator << (std::ostream & os,
const gotoxy & m);
private :
int m_x, m_y;
}; // gotoxy()
std::ostream & operator << (std::ostream & os, const gotoxy & m);
// La fonction
//
//===============================================//
// //
void SleepChronogram ( //
unsigned Num, //
unsigned & Col, //
char Status, //
unsigned Duree, //
boost::mutex & Mutex, //
unsigned Decal = 10u, //
unsigned Periode = 1u //
) //
throw (std::ios_base::failure); //
// //
//===============================================//
//
// fait dormir le thread qui l'appelle pendant Duree secondes au
// moyen de la fonction ::sleep().
//
// Elle est destinee a tracer des chronogrammes de threads pendant
// leur periode de sommeil, chronogrammes qui apparaissent comme
// dans l'exemple ci-dessous :
//
// ------------ Haut de l'ecran ----------------------
// ^
// |
// |
// Decal
// |
// |
// v
// AAADDDDD
// AAAADDDDD
// AAAAADDX
//
//------------- Bas de l'ecran -----------------------
//
// Status : caractere affiche en exclusion mutuelle.
// Il est sense representer l'etat courant du thread
// Mutex : mutex POSIX utilise pour l'affichage
// Periode : periodicite de l'affichage (en secondes)
// Duree : duree totale de l'affichage (= du sommeil du thread)
// Decal : nombre de lignes vierges en haut de l'ecran
// Num : numero de la ligne d'affichage sur laquelle est affiche
// le caractere Status.
// Le curseur apparait donc a la ligne (Decal + Num).
// Num est en general le numero du thread (e partir de 0).
// Col : en entree : colonne du premier affichage du caractere
// Status
// : en sortie : position du curseur en fin d'affichage
//
// La fonction Sleep () est susceptible de lever deux exceptions
// - std::ios_base::failure lors de l'injection du caractere
// - nsUtil::CExcFct lors du (de)-verrouillage du mutex
// (voir CException.h)
} // namespace nsUtil
#endif /* __SLEEP_CHRONOGR_H__ */
/**
*
* @file SleepChronogram.cpp
*
* @author M. Laporte, D. Mathieu
*
* @date 05/01/2007
*
* @version 2.0
*
* @brief SleepChronogr() affiche periodiquement un caractere
**/
#include <iostream>
#include <unistd.h> // sleep()
//#include "SleepChronogram.h"
using namespace std;
using namespace boost;
using namespace boost::posix_time;
string nsUtil::clrscr ("\033[2J"); // Clear screen
#define GOTOXY nsUtil::gotoxy
GOTOXY::gotoxy (int x, int y) : m_x (x), m_y (y) {}
ostream & nsUtil::operator << (ostream & os, const gotoxy & m)
{
return os << "\033[" << m.m_y << ';' << m.m_x << 'H';
}
#undef GOTOXY
void nsUtil::SleepChronogram (unsigned Num,
unsigned & Col,
char Status,
unsigned Duree,
boost::mutex & ioMutex,
unsigned Decal /* = 10u */,
unsigned Periode /* = 1u */)
throw (std::ios_base::failure)
{
for (unsigned i = Duree; i--; )
{
{
lock_guard <mutex> Lock (ioMutex);
cout << gotoxy (Col++, Num + Decal) << Status << flush;
}
this_thread::sleep (seconds (Periode));
}
} // SleepChronogr()
/**
* @file RDV_NThreadsBoost_c.cpp
*
* @author D. Mathieu
* M. Laporte
*
* @date 08/10/2008
*
* @brief Rendez-vous de N threads par la fonction barrier()
*
* Rendez-vous de N threads par la fonction barrier()
*
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/barrier.hpp>
//#include "SleepChronogram.h"
using namespace std;
using namespace boost;
using namespace nsUtil;
namespace
{
enum { KExcArg = 253 }; // Erreur d'arguments de main()
mutex io_Mtx;
barrier * pBarriere;
void RendezVous ()
{
pBarriere->wait();
} // RendezVous()
class CPassant
{
static unsigned s_ID;
unsigned m_ID;
unsigned m_DelaiAvant;
unsigned m_DelaiApres;
public :
CPassant (const CPassant & P)
: m_ID (P.m_ID),
m_DelaiAvant (P.m_DelaiAvant),
m_DelaiApres (P.m_DelaiApres) {}
CPassant (unsigned DelaiAvant, unsigned DelaiApres)
: m_ID (++s_ID),
m_DelaiAvant (DelaiAvant), m_DelaiApres (DelaiApres) {}
void operator () ()
{
unsigned Col (1);
SleepChronogram (m_ID, Col, 'A', m_DelaiAvant, io_Mtx);
RendezVous();
SleepChronogram (m_ID, Col, 'D', m_DelaiApres, io_Mtx);
SleepChronogram (m_ID, Col, 'X', 1, io_Mtx);
} // operator()
}; // CPassant
} // namespace
unsigned CPassant::s_ID (0);
int main (int argc, char * argv [])
{
if (argc != 1)
{
cerr << "Usage : RDV_NThreadsBoost\n";
return KExcArg;
}
unsigned NbThreads;
cin >> NbThreads;
pBarriere = new barrier (NbThreads);
vector <CPassant> VPassants;
VPassants.reserve (NbThreads);
for (unsigned DelaiAvant, DelaiApres, i (0); i < NbThreads; ++i)
{
cin >> DelaiAvant >> DelaiApres;
VPassants.push_back (CPassant (DelaiAvant, DelaiApres));
}
thread_group GrpThreads;
cout << clrscr << flush;
for (unsigned i = NbThreads; i--; )
GrpThreads.create_thread (VPassants [i]);
GrpThreads.join_all ();
cout << gotoxy (0, NbThreads + 12);
return 0;
} // main()
M4104C-boost-Exo3-Corrigé
/**
*
* @file sleepChronogram.h
*
* @author M. Laporte, D. Mathieu
*
* @date 05/01/2007
*
* @version 2.0
*
* @brief SleepChronogr() affiche periodiquement un caractere
**/
#if !defined __SLEEP_CHRONOGR_H__
#define __SLEEP_CHRONOGR_H__
#include <iostream> // ios_base::failure
#include <string>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
namespace nsUtil
{
// L'injection de la NTCTS
//
//=========================//
// //
extern std::string clrscr; //
// //
//=========================//
//
// vide l'ecran et positionne le curseur en haut a gauche
// La
//
//============//
// //
class gotoxy; //
// //
//============//
//
// est un injecteur qui positionne le curseur a l'ecran
// en position x et y :
//
// cout << gotoxy (10, 20) << ...
class gotoxy
{
public :
gotoxy (int x, int y);
friend std::ostream & operator << (std::ostream & os,
const gotoxy & m);
private :
int myx, myy;
}; // gotoxy()
std::ostream & operator << (std::ostream & os, const gotoxy & m);
// La fonction
//
//===============================================//
// //
void sleepChronogram ( //
unsigned num, //
unsigned & column, //
char status, //
unsigned oneDuration, //
boost::mutex & oneMutex, //
unsigned decal = 10u, //
unsigned period = 1u //
) //
throw (std::ios_base::failure); //
// //
//===============================================//
//
// fait dormir le thread qui l'appelle pendant oneDuration secondes au
// moyen de la fonction ::sleep().
//
// Elle est destinee a tracer des chronogrammes de threads pendant
// leur periode de sommeil, chronogrammes qui apparaissent comme
// dans l'exemple ci-dessous :
//
// ------------ Haut de l'ecran ----------------------
// ^
// |
// |
// decal
// |
// |
// v
// AAADDDDD
// AAAADDDDD
// AAAAADDX
//
//------------- Bas de l'ecran -----------------------
//
// status : caractere affiche en exclusion mutuelle.
// Il est sense representer l'etat courant du thread
// oneMutex : mutex POSIX utilise pour l'affichage
// period : periodicite de l'affichage (en secondes)
// oneDuration : duree totale de l'affichage (= du sommeil du thread)
// decal : nombre de lignes vierges en haut de l'ecran
// num : numero de la ligne d'affichage sur laquelle est affiche
// le caractere status.
// Le curseur apparait donc a la ligne (decal + num).
// num est en general le numero du thread (e partir de 0).
// column : en entree : colonne du premier affichage du caractere
// status
// : en sortie : position du curseur en fin d'affichage
//
// La fonction Sleep () est susceptible de lever deux exceptions
// - std::ios_base::failure lors de l'injection du caractere
// - nsUtil::CExcFct lors du (de)-verrouillage du mutex
// (voir CException.h)
} // namespace nsUtil
#endif /* __SLEEP_CHRONOGR_H__ */
/**
*
* @file sleepChronogram.cpp
*
* @author M. Laporte, D. Mathieu
*
* @date 05/01/2007
*
* @version 2.0
*
* @brief SleepChronogr() affiche periodiquement un caractere
**/
#include <iostream>
#include <unistd.h> // sleep()
//#include "sleepChronogram.h"
using namespace std;
using namespace boost;
using namespace boost::posix_time;
string nsUtil::clrscr ("\033[2J"); // Clear screen
#define GOTOXY nsUtil::gotoxy
GOTOXY::gotoxy (int x, int y) : myx (x), myy (y) {}
ostream & nsUtil::operator << (ostream & os, const gotoxy & m)
{
return os << "\033[" << m.myy << ';' << m.myx << 'H';
}
#undef GOTOXY
void nsUtil::sleepChronogram (unsigned num,
unsigned & column,
char status,
unsigned oneDuration,
boost::mutex & ioMutex,
unsigned decal /* = 10u */,
unsigned period /* = 1u */)
throw (std::ios_base::failure)
{
for (unsigned i = oneDuration; i--; )
{
{
lock_guard <mutex> oneLock (ioMutex);
cout << gotoxy (column++, num + decal) << status << flush;
}
this_thread::sleep (seconds (period));
}
} // SleepChronogram()
/**
* @file PoscineThreadsBoost.cpp
*
* @author D. Mathieu
* M. Laporte
*
* @date 23/09/2008
*
* @brief Simulation du fonctionnement d'une piscine
*
* Simulation du fonctionnement d'une piscine
* Gestion de plusieurs ressources de natures differentes
*/
#include <iostream>
#include <vector>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition.hpp>
//#include "CstCodErr.h"
//#include "SleepChronogram.h"
using namespace std;
using namespace boost;
using namespace nsUtil; // KExcArg
namespace
{
enum { KExcArg = 253 }; // Erreur d'arguments de main()
mutex io_Mtx;
mutex mtxCond;
condition_variable condition;
unsigned nbBaskets;
unsigned nbCubicles;
void beginUndressing (void)
{
unique_lock <mutex> oneLock (mtxCond);
while (nbCubicles == 0 || nbBaskets == 0) condition.wait (oneLock);
--nbBaskets;
--nbCubicles;
} // beginUndressing()
void endUndressing (void)
{
unique_lock <mutex> oneLock (mtxCond);
++nbCubicles;
condition.notify_all ();
} // endUndressing()
void beginDressingAgain (void)
{
unique_lock <mutex> oneLock (mtxCond);
while (nbCubicles == 0) condition.wait (oneLock);
--nbCubicles;
} // beginDressingAgain()
void endDressingAgain (void)
{
unique_lock <mutex> oneLock (mtxCond);
++nbCubicles;
++nbBaskets;
condition.notify_all ();
} // endDressingAgain()
class Bather
{
static unsigned s_ID;
unsigned myID;
unsigned myArrivalDuration;
unsigned myUndressingDuration;
unsigned myBathDuration;
unsigned myDressingAgainDuration;
unsigned myEndingDuration;
public :
Bather (unsigned arrivalDuration,
unsigned undressingDuration,
unsigned bathDuration,
unsigned dressingAgainDuration,
unsigned endingDuration)
: myID (++s_ID),
myArrivalDuration (arrivalDuration),
myUndressingDuration (undressingDuration),
myBathDuration (bathDuration),
myDressingAgainDuration (dressingAgainDuration),
myEndingDuration (endingDuration) {}
void operator ()()
{
unsigned Col (1);
sleepChronogram (myID, Col, 'A', myArrivalDuration,
io_Mtx);
beginUndressing();
sleepChronogram (myID, Col, 'D', myDressingAgainDuration, io_Mtx);
endUndressing ();
sleepChronogram (myID, Col, 'B', myBathDuration, io_Mtx);
beginDressingAgain ();
sleepChronogram (myID, Col, 'R', myDressingAgainDuration, io_Mtx);
endDressingAgain ();
sleepChronogram (myID, Col, 'Q', myEndingDuration, io_Mtx);
sleepChronogram (myID, Col, 'X', 1, io_Mtx);
} // operator()
}; // Bather
} // namespace
unsigned Bather::s_ID (0);
int main (int argc, char * argv [])
{
if (argc != 1)
{
cerr << "Usage : PiscineThreadsBoost\n";
return KExcArg;
}
unsigned nbThreads;
cin >> nbBaskets >> nbCubicles >> nbThreads;
cout << clrscr << flush;
vector <Bather> vBathers;
vBathers.reserve (nbThreads);
for (unsigned arrivalDuration, undressingDuration, bathDuration,
dressingAgainDuration, endingDuration, i (0); i < nbThreads; ++i)
{
cin >> arrivalDuration >> undressingDuration >> bathDuration
>> dressingAgainDuration >> endingDuration;
vBathers.push_back (
Bather (arrivalDuration, undressingDuration,
bathDuration, dressingAgainDuration, endingDuration));
}
thread_group grpThreads;
cout << clrscr << flush;
for (unsigned i = nbThreads; i--; )
grpThreads.create_thread (vBathers [i]);
grpThreads.join_all ();
cout << gotoxy (0, nbThreads + 12);
return 0;
} // main()
M4104C-boost-Exo4-Corrigé
/**
*
* @file CNpThreadsBoostV1.cpp
*
* @author D. Mathieu, M. Laporte
*
* @date 23/09/2008
*
* @version 2.0
*
* @brief Calcul parallele de CNp
*
**/
#include <iostream>
#include <vector>
#include <sstream>
#include <boost/thread/thread.hpp>
#include <boost/tr1/functional.hpp> // ou <functional>
//#include "CstCodErr.h"
using namespace std;
using namespace boost;
//using namespace nsUtil; // KExcArg
namespace
{
enum { KExcArg = 253 }; // Erreur d'arguments de main()
void CNp (unsigned N, unsigned p, unsigned * pRes)
{
if (N == p)
{
*pRes = 1;
return;
}
if (p == 1)
{
*pRes = N;
return;
}
unsigned r1;
unsigned r2;
thread_group groupThreads;
groupThreads.create_thread (bind (CNp, N - 1, p - 1, & r1));
groupThreads.create_thread (bind (CNp, N - 1, p , & r2));
groupThreads.join_all ();
*pRes = r1 + r2;
} // CNp()
} // namespace
int main (int argc, char * argv [])
{
if (argc != 3)
{
cerr << "Usage : " << argv [0] << " <N> <p>\n";
return KExcArg;
}
unsigned N;
{
istringstream is (argv [1]);
is >> N;
}
unsigned p;
{
istringstream is (argv [2]);
is >> p;
}
cout << "C (" << N << ", " << p << ") = " << flush;
unsigned result;
thread thr (bind (CNp, N, p, & result));
thr.join ();
cout << result << '\n';
return 0;
} // main()
M4104C-boost-Exo5-Corrigé
/**
*
* @file CNpThreadsBoostV2.cpp
*
* @author D. Mathieu, M. Laporte
*
* @date 09/03/2011
*
* @version 2.0
*
* @brief Calcul parallele de CNp avec "memoisation"
*
**/
#include <iostream>
#include <vector>
#include <sstream>
#include <boost/thread/thread.hpp>
#include <boost/tr1/functional.hpp> // ou <functional> : bind()
#include <boost/thread/locks.hpp>
#include <boost/thread/condition.hpp>
//#include "CstCodErr.h"
using namespace std;
using namespace boost;
//using namespace nsUtil; // KExcArg
namespace
{
enum { KExcArg = 253 }; // Erreur d'arguments de main()
int combin [100][100];
mutex mtx;
condition_variable condition;
void CNp (unsigned N, unsigned p, unsigned * pRes)
{
int result;
{
unique_lock <mutex> oneLock (mtx);
if ((result = combin [N][p]) > 0)
{
*pRes = result;
return;
}
if (result == 0)
{
while (combin [N][p] == 0) condition.wait (oneLock);
*pRes = combin [N][p];
return;
}
combin [N][p] = 0;
} // Liberation du lock
unsigned r1;
unsigned r2;
thread_group groupThreads;
groupThreads.create_thread (bind (CNp, N - 1, p - 1, & r1));
groupThreads.create_thread (bind (CNp, N - 1, p , & r2));
groupThreads.join_all ();
*pRes = r1 + r2;
{
lock_guard <mutex> oneLock (mtx);
combin [N][p] = *pRes;
}
condition.notify_all ();
} // CNp()
} // namespace
int main (int argc, char * argv [])
{
if (argc != 3)
{
cerr << "Usage : " << argv [0] << " <N> <p>\n";
return KExcArg;
}
unsigned N;
{
istringstream is (argv [1]);
is >> N;
}
unsigned p;
{
istringstream is (argv [2]);
is >> p;
}
cout << "C (" << N << ", " << p << ") = " << flush;
for (unsigned i = 1; i <= N; ++i)
{
combin [i][1] = i;
for (unsigned j = 2; j <= p; ++j) combin [i][j] = -1;
}
for (unsigned j = 1; j <= p; ++j) combin [j][j] = 1;
unsigned result;
thread Thr (bind (CNp, N, p, & result));
Thr.join ();
cout << result << '\n';
return 0;
} // main()
M4104C-boost-Exo6-Corrigé
/**
*
* @file BALMultiThreadsBoost.cpp
*
* @author D. onethieu, M. Laporte
*
* @date 19/10/2008
*
* @version 1.0
*
* @brief Boite a lettres generique
*
**/
#include <iostream>
#include <cstdlib> // srand(), rand()
#include <ctime> // time()
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
//#include "nsUtil.h"
using namespace std;
using namespace boost;
using namespace boost::posix_time; // time_duration
//using namespace nsUtil;
namespace
{
typedef string CMessage;
mutex myMtxKeyBoard;
mutex myMtxScreen;
template <class Letter>
class LetterboxGen
{
condition_variable myCondVarProd;
condition_variable myCondVarConsum;
mutex myMtxCondVar;
Letter myLetter;
bool myIsEmpty;
public :
LetterboxGen (void) : myIsEmpty (true) {}
void push (const Letter & oneLetter, system_time & stamp)
{
{
unique_lock <mutex> oneLock (myMtxCondVar);
if (!myIsEmpty) myCondVarProd.wait (oneLock);
stamp = get_system_time();
myLetter = oneLetter;
myIsEmpty = false;
}
myCondVarConsum.notify_one();
} // push()
Letter pop (system_time & stamp)
{
Letter oneLetter;
{
unique_lock <mutex> oneLock (myMtxCondVar);
if (myIsEmpty) myCondVarConsum.wait (oneLock);
stamp = get_system_time();
oneLetter = myLetter;
myIsEmpty = true;
}
myCondVarProd.notify_one();
return oneLetter;
} // pop()
}; // LetterboxGen
typedef LetterboxGen <CMessage> LetterboxString;
LetterboxString theBox;
unsigned rand (unsigned min, unsigned max)
{
return std::rand () % (max - min) + min;
} // rand()
class Producer
{
static unsigned s_ID;
unsigned myID;
public :
Producer (void) : myID (++s_ID) {}
void operator() (void)
{
system_time stamp;
string oneLetter;
for ( ; ; )
{
{
lock_guard <mutex> oneLock (myMtxKeyBoard);
cin >> oneLetter;
}
if (cin.eof ()) break;
this_thread::sleep (seconds (rand (1, 5)));
theBox.push (oneLetter, stamp);
{
lock_guard <mutex> oneLock (myMtxScreen);
cout << stamp << " : Prod. " << myID
<< " a déposé : " << oneLetter << '\n';
}
this_thread::sleep (seconds (rand (1, 5)));
}
{
lock_guard <mutex> oneLock (myMtxScreen);
cout << "Producteur " << myID << " se termine\n";
}
} // operator ()
}; // Producer
class Consumer
{
static unsigned s_ID;
unsigned myID;
public :
Consumer (void) : myID (++s_ID) {}
void operator() (void)
{
system_time stamp;
string oneLetter;
for ( ; ; )
{
this_thread::sleep (seconds (rand (1, 5)));
oneLetter = theBox.pop (stamp);
{
lock_guard <mutex> oneLock (myMtxScreen);
cout << stamp << " : Cons. " << myID
<< " a retiré : " << oneLetter << '\n';
}
this_thread::sleep (seconds (rand (1, 5)));
}
} // operator ()
}; // Consumer
unsigned Producer ::s_ID (0);
unsigned Consumer::s_ID (0);
} // namespace
int main()
{
srand (time (nullptr));
unsigned NbConsumateurs = 3;
unsigned NbProducteurs = 2;
vector <thread *> VThreads;
for (unsigned i = NbProducteurs; i--; )
VThreads.push_back (new thread (Producer()));
for (unsigned i = NbConsumateurs; i--; )
VThreads.push_back (new thread (Consumer()));
for (unsigned i = NbProducteurs + NbConsumateurs; i--; )
VThreads[i]->join ();
return 0;
} // main()
M4104C-boost-Exo7-Corrigé
/**
*
* @file IterArbreThreadsBoost.cpp
*
* @author D. onethieu
*
* @date 21/10/2008
*
* @version 1.0
*
* @brief Iterateur a travers un arbre de recherche
*
**/
#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/tr1/functional.hpp> // ou <functional> : bind()
using namespace std;
using namespace boost;
using namespace boost::posix_time; // time_duration
namespace
{
template <class Letter>
class MailboxGen
{
condition_variable myCondVarProd;
condition_variable myCondVarConsum;
mutex myMtxCondVar;
Letter myLetter;
bool myIsEmpty;
public :
MailboxGen (void) : myIsEmpty (true) {}
void push (const Letter & oneLetter)
{
{
unique_lock <mutex> oneLock (myMtxCondVar);
if (!myIsEmpty) myCondVarProd.wait (oneLock);
myLetter = oneLetter;
myIsEmpty = false;
}
myCondVarConsum.notify_one();
} // push()
Letter pop (void)
{
Letter oneLetter;
{
unique_lock <mutex> oneLock (myMtxCondVar);
if (myIsEmpty) myCondVarConsum.wait (oneLock);
oneLetter = myLetter;
myIsEmpty = true;
}
myCondVarProd.notify_one();
return oneLetter;
} // pop()
}; // MailboxGen
typedef MailboxGen <int> MailboxInt;
class Node;
class SearchTree;
class IterTree;
typedef Node * pNode_t;
class Node
{
int myValue;
pNode_t myLeftSon;
pNode_t myRightSon;
public :
pNode_t getLeftSon (void) const { return myLeftSon; }
pNode_t getRightSon (void) const { return myRightSon; }
void setLeftSon (pNode_t LeftSon) { myLeftSon = LeftSon; }
void setRightSon (pNode_t RightSon) { myRightSon = RightSon; }
Node (int value, pNode_t LeftSon = 0, pNode_t RightSon = 0)
: myValue (value), myLeftSon (LeftSon), myRightSon (RightSon) {}
int getValue (void) const { return myValue; }
}; // Node
class SearchTree
{
friend class IterTree;
pNode_t myRoot;
pNode_t addNode (int value, pNode_t root)
{
if (! root) return new Node (value);
if (value < root->getValue())
root->setLeftSon (addNode (value, root->getLeftSon()));
else
root->setRightSon (addNode (value, root->getRightSon()));
return root;
} // addNode()
public :
SearchTree (void) : myRoot (0) {}
void addNode (int value)
{
myRoot = addNode (value, myRoot);
} // addNode()
}; // SearchTree
class IterTree
{
MailboxGen <pNode_t> myMailbox;
SearchTree * myPTree;
void travel (pNode_t root)
{
if (!root) return;
travel (root->getLeftSon());
myMailbox.push (root);
travel (root->getRightSon());
} // travel()
void travel ()
{
travel (myPTree->myRoot);
myMailbox.push (0);
} // travel()
static void travelThr (IterTree * pIter)
{
cout << "\nDebut du parcours\n";
pIter->travel ();
cout << "\nFin du parcours\n";
} // travelThr()
public :
IterTree (SearchTree & tree)
: myPTree (& tree)
{
new thread (bind (travelThr, this));
} // IterTree()
pNode_t getNext (void)
{
return myMailbox.pop();
} // getNext()
}; // IterTree
SearchTree oneTree;
class Reader
{
static unsigned s_ID;
unsigned myID;
public :
Reader (void) : myID (++s_ID) {}
void operator () (void)
{
cout << "\nDebut du lecteur " << myID << '\n';
IterTree Iter (oneTree);
for (pNode_t Ptr; (Ptr = Iter.getNext()); )
{
cout << "Valeur lue par lecteur " << myID << " : "
<< Ptr->getValue() << '\n';
this_thread::sleep (seconds (1));
}
cout << "\nFin du lecteur " << myID << '\n';
} // operator()
}; // Reader
unsigned Reader::s_ID = 0;
} // namespace
int main(void)
{
int Tab [10] = { 1, 5, 3, 6, 7, 3, 4, 11, 9, 2};
for (unsigned i (0); i < 10; ++i) oneTree.addNode (Tab [i]);
thread_group groupThreads;
groupThreads.create_thread (Reader ());
this_thread::sleep (seconds (2));
groupThreads.create_thread (Reader ());
groupThreads.join_all ();
return 0;
} // main()
M4104C-boost-Exo8-Corrigé
/**
*
* @file CCppAndThreads_a.cpp
*
* @authors D. Mathieu
*
* @date 03/02/2010
*
* @version V3.0
*
* @brief strtok() thread-safe ?
*
**/
#include <iostream>
#include <sstream>
#include <string>
#include <cstring> // strcpy(), strtok()
#include <vector>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/tr1/functional.hpp> // ou <functional> pour bind()
using namespace std;
using namespace boost;
enum {KErrArg = 253 };
namespace
{
typedef vector <char *> VpChar;
const char * punct = " ";
mutex io_Mtx;
void fThread (const string * param)
{
char * oneString = new char [param->size() + 1];
strcpy (oneString, param->c_str());
/* Affichage de la NTCTS locale * /
{
lock_guard <mutex> oneLock (io_Mtx);
cout << oneString << endl;
}
/* */
VpChar tab;
/* * /
for (tab.push_back (strtok (oneString, punct));
tab.back();
tab.push_back (strtok (0, punct)));
tab.pop_back(); // suppression du dernier pointeur (nul)
/* */
/* */
char * buffer;
for (tab.push_back (strtok_r (oneString, punct, &buffer));
tab.back();
tab.push_back (strtok_r (0, punct, &buffer)));
tab.pop_back(); // suppression du dernier pointeur (nul)
/* * /
/* */
{
lock_guard <mutex> oneLock (io_Mtx);
cout << "Nombre de mots : " << tab.size() << '\n';
}
/* */
delete [] oneString;
/* */
} // fThread()
} // namespace
int main (int argc, char * argv [])
{
if (2 != argc)
{
cerr << "Usage : " << argv [0] << " <Nb_threads>\n";
return KErrArg;
}
unsigned nbThreads;
{
istringstream is (argv [1]);
is >> nbThreads;
}
string line;
for (unsigned i (200000) ; i--; ) line += "Toto ";
thread_group groupThreads;
for (unsigned i = nbThreads; i--; )
{
groupThreads.add_thread (new thread (bind <void> (fThread, & line)));
}
groupThreads.join_all ();
return 0;
} // main()