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