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