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