#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>

#define SLEEP 1
#define WANT 2

int run = 1;

pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t m3 = PTHREAD_MUTEX_INITIALIZER;

char state[] = "r1   t1   r2   t2   r3   t3   r1";

int choose(int n){ return rand()%n+1; }

void* tf1 (void*p) {
  while(run)
  {
    switch(choose(2))
    {
      case SLEEP: sleep(2*choose(3)); break;
      case WANT:
        state[3]='w'; pthread_mutex_lock(&m1); state[3]='-';
        state[8]='w'; pthread_mutex_lock(&m2); state[8]='-';
        state[5]='T'; sleep(2*choose(5));
        pthread_mutex_unlock(&m1); pthread_mutex_unlock(&m2);
        state[3]=' '; state[8]=' '; state[5]='t';
        break;
    }
  }
  return NULL;
}

void* tf2 (void*p) {
  while(run)
  {
    switch(choose(2))
    {
      case SLEEP: sleep(2*choose(3)); break;
      case WANT:
        state[13] = 'w'; pthread_mutex_lock(&m2); state[13] = '-';
        state[18] = 'w'; pthread_mutex_lock(&m3); state[18] = '-';
        state[15]='T'; sleep(2*choose(5));
        pthread_mutex_unlock(&m2); pthread_mutex_unlock(&m3);
        state[13]=' '; state[18]=' '; state[15]='t';
        break;
    }
  }
  return NULL;
}

void* tf3 (void*p) {
  while(run)
  {
    switch(choose(2))
    {
      case SLEEP: sleep(2*choose(3)); break;
      case WANT:
        state[23]='w'; pthread_mutex_lock(&m3); state[28]='-';
        state[28]='w'; pthread_mutex_lock(&m1); state[23]='-';
        state[25]='T'; sleep(2*choose(5));
        pthread_mutex_unlock(&m1); pthread_mutex_unlock(&m3);
        state[23]=' '; state[28]=' '; state[25]='t';
        break;
    }
  }
  return NULL;
}

int main (int argc, char* argv[]) {
  pthread_t t1, t2, t3; int round = 0;

  srand(time(0));
  pthread_create(&t1,NULL,&tf1,NULL);
  pthread_create(&t2,NULL,&tf2,NULL);
  pthread_create(&t3,NULL,&tf3,NULL);

  while(round<24) {
     printf("Round %2d: %s\n", round+1, state);
     sleep(2);
     round++;
  }
  run = 0;

  pthread_join(t1,NULL); pthread_join(t2,NULL);
  pthread_join(t3,NULL);
  return 0;
}