/*
Examine Multiprocessor issues using
threads to simulate multiple CPU's
*/
//#include "../inc/local_mutex.h"
#include <pthread.h>
#include <fcntl.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
/*
#define DEBUG 1
#define TRACE 1
#include "../inc/types.h"
#include "../inc/debug.h"
*/
#define enter(a)
#define rtnval(a) return(a)
#define rtn_noval(a) return
#define TRUE 1
#define FALSE 0
#define Log_debug(b)
static char const ident[] =
"$Id: lab4_1.c,v 1.1 2004/04/13 01:36:19 gmiller Exp $";
void *do_one_thing (int *);
void *do_another_thing (int *);
void do_wrap_up (int, int);
pthread_cond_t start_cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t start_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t done_cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t done_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
int r1 = 0, r2 = 0, done = 0;
/*
Funtion to implement a "pretty" version of the output
code so that the main functions do get too UGLY.
*/
void
t_printf (char *fmt, ...)
{
va_list ap;
static char my_fn[] = "t_printf";
//enter(my_fn);
pthread_mutex_lock (&print_mutex);
va_start (ap, fmt);
vprintf (fmt, ap);
va_end (ap);
fflush (stdout);
pthread_mutex_unlock (&print_mutex);
//rtn_noval();
}
/*
Process 1 CPU work
*/
void *
do_one_thing (int *pnum_times)
{
int i, j, x;
static char my_fn[] = "do_one_thing";
enter(my_fn);
/*
Lock start_mutex so we can wait for
a startup signal on the condition variable.
*/
pthread_mutex_lock (&start_mutex);
t_printf ("waiting do_one_thing\n");
fflush (stdout);
/*
pthread_cond_wait set's up wait on condition
variable and unlocks the mutex and then waits
for the condition variable to signal. Then it
will lock the mutex
*/
pthread_cond_wait (&start_cv, &start_mutex);
/*
Ok ... we got control of the mutex so it is
locked. We don't need it locked so we unlock
it to allow another thread to do it's thing.
*/
pthread_mutex_unlock (&start_mutex);
/*
Since our threads can do printf over each other
I have chosen to control output with a mutex
so none of the messages from each thread will
over-write each other.
** Note **
This should be done in a function or macro to
keep from making the code so UGLY.
*/
//sleep(1);
t_printf ("Starting ... do_one_thing\n");
Log_debug ("Starting ... do_one_thing");
for (i = 0; i < 100; i++) {
t_printf ("+");
for (j = 0; j < 100000; j++)
x = x + i;
(*pnum_times)++;
}
Log_debug ("Ready to lock done in do_one_thing");
pthread_mutex_lock (&done_mutex);
Log_debug ("Done locked in do_one_thing");
t_printf ("@(");
done++;
Log_debug ("Send signal for done in do_one_thing");
pthread_cond_signal (&done_cv);
Log_debug ("Sent signal for done in do_one_thing");
Log_debug ("Ready to unlock done in do_one_thing");
pthread_mutex_unlock (&done_mutex);
Log_debug ("Done unlocked in do_one_thing");
t_printf ("!(");
// sleep (10);
pthread_exit ((void *) NULL);
rtnval(NULL);
}
void *
do_another_thing (int *pnum_times)
{
int i, j, x;
static char my_fn[] = "do_another_thing";
enter(my_fn);
pthread_mutex_lock (&start_mutex);
t_printf ("waiting do_another_thing\n");
fflush (stdout);
pthread_cond_wait (&start_cv, &start_mutex);
pthread_mutex_unlock (&start_mutex);
//sleep(1);
t_printf ("Starting ... do_another_thing\n");
Log_debug ("Starting ... do_another_thing");
for (i = 0; i < 100; i++) {
t_printf ("-");
for (j = 0; j < 100000; j++)
x = x + i;
(*pnum_times)++;
}
Log_debug ("Ready to lock done in do_another_thing");
pthread_mutex_lock (&done_mutex);
Log_debug ("Done locked in do_another_thing");
t_printf ("@)");
done++;
Log_debug ("Send signal for done in do_another_thing");
pthread_cond_signal (&done_cv);
Log_debug ("Sent signal for done in do_another_thing");
Log_debug ("Ready to unlock done in do_another_thing");
pthread_mutex_unlock (&done_mutex);
Log_debug ("Done unlocked in do_another_thing");
t_printf ("!)");
// sleep (10);
pthread_exit ((void *) NULL);
rtnval(NULL);
}
void
do_wrap_up (int one_times, int another_times)
{
int total;
static char my_fn[] = "do_wrap_up";
enter(my_fn);
t_printf ("\n");
total = one_times + another_times;
t_printf ("wrap up: doing another %d, another %d, total %d\n",
one_times, another_times, total);
fflush (stdout);
rtn_noval();
}
int
main ()
{
pthread_t thread1, thread2;
int complete = FALSE;
static char my_fn[] = "lab4_1";
enter(my_fn);
// set_debug ();
pthread_create (&thread1, NULL, (void *) do_one_thing, (void *) &r1);
pthread_create (&thread2, NULL, (void *) do_another_thing, (void *) &r2);
sleep (5);
t_printf ("Ready to start threads ..... \n");
fflush (stdout);
pthread_mutex_lock (&start_mutex);
pthread_cond_broadcast (&start_cv);
pthread_mutex_unlock (&start_mutex);
while (complete == FALSE) {
t_printf ("&");
Log_debug ("Inside check loop");
/*
Condition wait required the mutex to be locked before the call
so the conf=dition variable can be modified. After the modification
the mutex is unlocked to initiate the wait. When woken up the
mutex is again locked to that we have freedom to checke the condition
variaible again.
*/
pthread_mutex_lock (&done_mutex);
if (done >= 2) {
complete = TRUE;
pthread_mutex_unlock (&done_mutex);
continue;
}
Log_debug ("Now do cond_wait");
pthread_cond_wait (&done_cv, &done_mutex);
Log_debug ("cond_wait complete");
t_printf ("%");
if (done >= 2)
complete = TRUE;
Log_debug ("1. Done needs unlocking");
pthread_mutex_unlock (&done_mutex);
Log_debug ("1. Done is unlocked");
t_printf ("#");
}
//sleep(1);
Log_debug ("Loop has exited");
t_printf ("^");
t_printf ("\nAll threads complete\n");
fflush (stdout);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
do_wrap_up (r1, r2);
fflush (stdout);
rtnval(0);
}