This is a version of the conc.c example program with most of
the code that prints messages stripped out. Some other "extras"
were removed too -- nothing important to what the program does.
You may wish to study this version before sifting through
conc.c.
Latest Revision: 11/08/99
11/08/99 -- correction to the include directives
11/08/99 -- added casts to parameters of cthread_fork()
11/08/99 -- fixed typo that was preventing the program from terminating.
#include <stdio.h>
#include <mach/cthreads.h>
#include "sem.h"
extern sim_semaphore create_sim_sem() ;
extern void wait_sem() ;
extern void signal_sem() ;
int checking ; /* Set this to 1 if you want lots of
"debug printf's". */
mutex_t stdoutLock ; /* When debugging, we need to use this
lock to get intelligible printouts
of what the various threads are
doing. Warning: Don't change how
this is done until you've thought a
WHOLE lot about the consequences. */
int count; /* number of child threads active */
sim_semaphore countSem ; /* For synchronization. */
sim_semaphore finished ; /* To provide a condition for the
mother to wait on. */
extern long random(void);
void init()
{
checking = 0 ; /* JUST FOR DEBUGGING: change to
1 if you want messages. */
stdoutLock = mutex_alloc() ;
count = 0; /* counter: current number
of children. */
countSem = create_sim_sem(1) ; /* initialize the semaphore
for access to counter */
finished = create_sim_sem(0) ; /* initialize "finished" to 0
to force a block if no signal
has been done first. */
srandom(time((int *) 0)); /* initialize random
number generator */
}
/*
* Each child just counts up to its argument, yielding the
* processor on each iteration. When it's finished, it
* decrements the global count and signals that it's done.
*/
void child(int n)
{
int i, temp ;
for (i = 0; i < n; i += 1)
{
cthread_yield();
}
mutex_lock (stdoutLock) ;
printf("Child %d has finished his work ", cthread_self());
printf("of %d cycles.\n", n);
fflush(stdout) ;
mutex_unlock(stdoutLock) ;
/*
* If any thread wants to access the count variable, it
* first waits on countSem to insure exclusive access.
*/
wait_sem(countSem);
count -= 1 ;
/* signal mother to exit if last thread is done */
if (count == 0)
{
signal_sem(finished);
}
signal_sem(countSem);
mutex_lock (stdoutLock) ;
printf("Child %d EXITS.\n", cthread_self());
fflush(stdout) ;
mutex_unlock(stdoutLock) ;
cthread_exit(0);
}
/*
* The mother spawns a given number of children and then waits
* for them all to finish.
*/
void mother(int nchildren)
{
int i, cnt_cpy;
mutex_lock (stdoutLock) ;
printf("Mother will spawn %d children.\n", nchildren);
fflush(stdout) ;
mutex_unlock(stdoutLock) ;
for (i = 1; i <= nchildren; i += 1)
{
wait_sem(countSem);
/* Increment count with the creation of each child
thread. */
count += 1;
/* Fork a child and detach it, since the mother never
joins it individually. */
cthread_detach(cthread_fork( (cthread_fn_t) child,
(any_t) (random() % 1000)));
signal_sem(countSem);
}
/*
* Mother thread loops waiting on the semaphore "finished".
* When a child signals on "finished", the mother thread
* tests the count for a value of zero.
*/
do
{
wait_sem(countSem) ;
cnt_cpy = count ;
signal_sem(countSem) ;
if (cnt_cpy != 0)
{
wait_sem(finished) ;
}
}
while (cnt_cpy != 0) ;
mutex_lock (stdoutLock) ;
printf("All %d children have finished.\n", nchildren);
printf("Mother %d now EXITS.\n", cthread_self() );
fflush(stdout) ;
mutex_unlock(stdoutLock) ;
cthread_exit(0);
}
main()
{
init();
/* create mother thread and up to 15 children */
mother((int) random() % 16);
}