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