M4104C-boost-Exo1-Corrigé

/**
 * @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()





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()