/************************************************************
 * file: thread.cc
 * Visualization Course, Fall 2001
 * Author: Ting-Jen Yen (yentj@cs.nyu.edu), modified by Chee
 *
 *      A basic demo of posix threads.
 *	In this simple example, we only create one thread (called
 *		the "child thread".  The main program serves as the
 *		other thread, "main thread". 
 *	The two thread are trying to increment a shared variable
 *		"a" for N=8 and M=12 times (resp.) each.  To ensure mutual 
 *		exclusion, it must first grab a mutex variable (mutex1)
 *		before incrementing a.  At the end of the
 *		program, the value of a should be N+M = 20.
 *		But the order in which the 2 threads access a is
 *		unpredictable.
 *
 *	Compile with
 *		cygwin:  > gcc $(OPT) thread.c -o thread
 *		solaris: > gcc $(OPT) -lpthread -lposix4 thread.c -o thread
 *
 *	NOTE:	If OPT is the empty string (or undefined), then the child 
 *		thread will be scheduled more aggressively than the main 
 *		thread.  But if OPT = -D_YIELD, then both threads will be 
 *		scheduled equally.  See the code below to see why this is so.
 *
 ************************************************************/

#include 
#include 
#include 
#include 
#include 

void * mythread(void *);	// forward declaration
void   mainFunc(void);		// forward declaration
pthread_mutex_t mutex1;		// mutex object
int a;				// shared variable

/************************************************************
 Main Program
 ************************************************************/

main()
{
  pthread_t p_id;				// thread object
  pthread_create(&p_id, NULL,  mythread, NULL);	// create it
  pthread_mutex_init(&mutex1, NULL);		// initialize mutex object
  a= 0;
  mainFunc();					// the "main thread"
  pthread_join(p_id, NULL);			// wait for child thread to end
}

/************************************************************
 Child Thread
 ************************************************************/

void * mythread(void *rt)
{
  int i;
  puts("Child thread starts");
  for (i = 0 ; i < 8; i ++)
  {
    pthread_mutex_lock(&mutex1);		// grab mutex1
    a ++;					// increment "a"
    printf("Child thread:  a = %d\n", a);	// prints "a"
    pthread_mutex_unlock(&mutex1);		// release mutex1
#ifdef _YIELD
    sched_yield();				// gives fairer scheduling
#endif
  }
  puts("Child thread done");
  pthread_exit(NULL);
}// mythread

/************************************************************
 Main Thread Function
 ************************************************************/

void mainFunc(void)
{
  char s[80];
  int i=0;
  puts("Main thread starts");
  for (i = 0 ; i < 12; i ++)
  {
    pthread_mutex_lock(&mutex1);	// enter critical section
    a ++;
    printf("Main Thread:  a = %d\n", a);
    pthread_mutex_unlock(&mutex1);	// exit critical section
#ifdef _YIELD
    sched_yield();			// main thread always yields
#endif
  }
  puts("Main thread done");
  pthread_mutex_destroy(&mutex1);
}//mainFunc

/************************************************************
 END
 ************************************************************/