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