(Latest Revision -- 08/18/2000)

HiHo.cpp

/*     

       This is a very simple program that illustrates the use of semaphores
       to synchronize the actions of two threads in the same task.  Two
       threads write to the standard output.  They synchronize their
       actions in such a way that the output strictly alternates between
       the two.

*/

#include <sched.h>
#include <time.h>
#include <iostream>
#include <pthread.h>
#include "sem.h"

using namespace std ;

/* ######################################## */
/*             Global Variables             */
/* ######################################## */

      /* HiTurn and HoTurn are semaphores this program uses to synchronize
         two threads. */

sim_semaphore   HiTurn ; 
sim_semaphore   HoTurn ;

      /* ho_t is a global variable to represent the dynamically-created
         thread */

pthread_t ho_t ; 


/* ######################################## */
/*      "Special"   Global Variables        */
/* ######################################## */

/* Two variables below are not used in this simple program, but the code in
   sem.cpp "expects" them to be here. */

         /* "Checking" is just a flag that you set to 1 if you want lots of
            debugging messages and set to 0 otherwise.  The semaphore code
            in sem.cpp imports "checking".  Therefore the semaphore
            operations will write lots of messages if you set checking=1.
            */

int checking ; 

      /* In some programs, we use the "stdoutLock" variable declared below
         to get intelligible printouts from multiple concurrent threads
         that write to the standard output.  (There has to be something to
         prevent the output of the threads from interleaving unintelligibly
         on the standard output, and we can't use semaphores if the
         semaphore code is writing messages too.)

         To print a message to standard output, a thread first locks
         standard output, then writes, then unlocks standard output.  See
         files sem.cpp or conc.cpp for examples of code that write messages
         in this manner.

         WARNING:  DON'T change how the locking of standard output is done
         until you've thought a WHOLE lot about the consequences.  In
         particular, using semaphores to do the job of stdoutLock can cause
         "infinite recursion" under certain circumstances.  The reason is
         that the semaphore code itself imports "stdoutLock" and writes
         messages when the "checking" variable is set to 1. */

pthread_mutex_t stdoutLock ;

/* ################################################## */
/*                         init                       */
/* ################################################## */
void init() 
{
  checking = 0 ;

  if ( 0!=pthread_mutex_init(&stdoutLock, NULL) )
  {  cout << "MUTEX INITIALIZATION FAILURE!" << endl;
     exit(-1) ;}
     
  HiTurn = create_sim_sem(1) ;
  HoTurn = create_sim_sem(0) ;
}

/* ################################################## */
/*                          Ho                        */
/* ################################################## */
/*

     The thread that executes "Hi" spawns a child thread that executes this
     function.  This function writes "Ho there!" in strict alternation with
     the other thread, which writes "Hi there!"

*/
void * Ho(void * ignore)
{
  int i, j ;
  for (i = 0; i < 25; i += 1) 
  {
    wait_sem (HoTurn) ;
             /* delay */
    for (j = 0; j < 300 ; j += 1) sched_yield();
    cout << "Ho there!" << endl ;
    signal_sem (HiTurn) ;  
  }
}

/* ################################################## */
/*                          Hi                        */
/* ################################################## */
/*

     Spawn a second thread.  Then synchronize with it so that messages from
     the two threads alternate strictly.  This function writes "Hi there!"

*/
void Hi() 
{ 
        int i;

        if (0!=pthread_create(&ho_t, NULL, Ho, (void *) 0))
        {  cout << "THREAD CREATION FAILURE!" << endl;
           exit(-1) ;}
     
        if (0!=pthread_detach(ho_t))
        {  cout << "THREAD DETACHMENT FAILURE!" << endl ;
           exit(-1) ;}

        for (i = 0; i < 25; i += 1) 
        {
          wait_sem (HiTurn) ; 
          cout << "Hi there!" << endl;
          signal_sem (HoTurn) ;  
        }
        wait_sem (HiTurn) ; 
}

/* ################################################## */
/*                         Main                       */
/* ################################################## */
main() 
{ 
        init(); 
        Hi() ;
}