/*


    cond.cc

    C++ source for POSIX thread condition variable tests.

    Copyright (C) 1999 by Matt Roberts, KK5JY,
    All rights reserved


*/


#include <pthread.h>
#include <semaphore.h>
#include <iostream.h>
#include <stdio.h>
#include <unistd.h>

#ifndef NUM_THREADS
  #define NUM_THREADS (4)
#else
  #error NUM_THREADS already defined!
#endif

int x = 0;
pthread_mutex_t cm = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;

void report (char *message) {
  static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_lock (&m);
  cout << message;
  pthread_mutex_unlock (&m);
}

void *thread_func (void *data) {
  int id = *((int*)(data));
  char buffer [80];
  sprintf (buffer, "Thread %d started.\n", id); report (buffer);
  pthread_mutex_lock (&cm);
  sprintf (buffer, "Thread %d has aquired mutex for condition variable.\n", id); report (buffer);
  while (x != id) {
    sprintf (buffer, "Thread %d rejects predicate...going to sleep.\n", id); report (buffer);
    pthread_cond_wait (&cv, &cm);
  }
  sprintf (buffer, "Thread %d accepts predicate...doing something useful.\n", id); report (buffer);
  sleep (1);
  pthread_mutex_unlock (&cm);
  sprintf (buffer, "Thread %d exit.\n", id); report (buffer);
  pthread_exit (0);
}

int main (int argc, char **argv, char **envp) {
  pthread_t thread [NUM_THREADS];
  pthread_attr_t ta [NUM_THREADS];
  int id [NUM_THREADS];
  int input;
  int i;

  for (i = 0; i < NUM_THREADS; i++) {
    id [i] = i + 1;
  }
  
  for (i = 0; i < NUM_THREADS; i++) {
    pthread_create (thread + i, 0, thread_func, (void*)(id + i));
  }

  while (x != 999) {
    report ("Enter thread id: ");
    cin >> input;
    pthread_mutex_lock (&cm);
    x = input;
    pthread_cond_broadcast (&cv);
    pthread_mutex_unlock (&cm);
  }

  for (i = 0; i < NUM_THREADS; i++) {
    pthread_join (*(thread + i), 0);
  }
}
