/* a simple producer/consumer using semaphores and threads
   this illustrates the use of the times() function to do timing

   gcc thisfile.c -lpthread -lposix4
   a.out numIters
*/
 
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <sys/times.h>
#define SHARED 1

void *Producer(void *);
void *Consumer(void *);

sem_t empty, full;    /* the global semaphores */
int data;
int numIters;

/* main() -- read command line and create threads, then
             print result when the threads have quit */
int main(int argc, char *argv[]) {
  pthread_t pid, cid;    /* thread ids and attributes */
  pthread_attr_t attr;

  struct tms buffer;    /* used for timing */
  clock_t startTime, endTime;

  pthread_attr_init(&attr);
  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

  numIters = atoi(argv[1]);
  sem_init(&empty, SHARED, 1);  /* sem empty = 1 */
  sem_init(&full, SHARED, 0);   /* sem full = 0  */

  startTime = times(&buffer);
  pthread_create(&pid, &attr, Producer, NULL);
  pthread_create(&cid, &attr, Consumer, NULL);
  pthread_join(pid, NULL);
  pthread_join(cid, NULL);
  endTime = times(&buffer);
  printf("number of seconds:  %f\n",
         (float) (endTime-startTime)/CLK_TCK);
}

void *Producer(void *arg) {
  int produced;
  printf("Producer created\n");
  for (produced = 0; produced < numIters; produced++) {
    sem_wait(&empty);
    data = produced;
    sem_post(&full);
  }
}

void *Consumer(void *arg) {
  int total = 0, consumed;
  printf("Consumer created\n");
  for (consumed = 0; consumed < numIters; consumed++) {
    sem_wait(&full);
    total = total+data;
    sem_post(&empty);
  }
  printf("for %d iterations, the total is %d\n", numIters, total);
}
