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