/* pthreadmutex.c - a demo of pthread mutual exclusion */
#include <pthread.h>
#include <stdlib.h> /* for random() */
#include <stdio.h> /* for printf() */
#include <unistd.h> /* for sleep() */

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* declare the mutex globally */

void CriticalSection(int num)
{
  printf("Thread %d is in its critical section\n", num);
  sleep(random() % 4);  /* sleep for zero to four seconds */
  printf("Thread %d is leaving its critical section\n", num);
}

void NonCriticalSection(int num)
{
  printf("Thread %d is in its noncritical section\n", num);
  sleep(random() % 4);   /* sleep for zero to four seconds */
  printf("Thread %d is leaving its noncritical section\n", num);
}

void* ThreadController(void *arg)
{
  int *num = (int *)malloc(sizeof(int));
  int i;
  *num = *(int *)arg;
  for (i=0;i < 4;i++) {
    NonCriticalSection(*num);
    pthread_mutex_lock(&mutex);
    CriticalSection(*num);
    pthread_mutex_unlock(&mutex);
  }
  pthread_exit(num);
  return num; /* we never get here */
}

int main()
{
  int i;
  int retval;
  int *arg;
  pthread_t threadid[5];

  for (i=0;i < 5;i++) {  /* create five threads */
    arg = (int *)malloc(sizeof(int));
    *arg = i+1;
    retval = pthread_create(&threadid[i],NULL, ThreadController,arg);
    if (retval != 0) {
      fprintf(stderr,"ERROR creating thread");
    }
    
  } 
  for (i=0;i<5;i++) {
    arg = (int *) malloc(sizeof(int));
    retval = pthread_join(threadid[i],(void **)&arg);
    if (retval == 0)
      printf("Thread %d finished with value %d\n",
	     i, *arg);
    else
      fprintf(stderr,"ERROR on join");
  }
  return 0;
}
