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

#define MAXNITEMS	2000000
#define MAXNTHREADS	50
#define MIN(A, B) ((A) > (B) ? (B) : A)

int nitems;
/* Read only */
struct {
     pthread_mutex_t mutex; 
     int             buff[MAXNITEMS];
     int             nput;
     int             nval;
} shared = {
     PTHREAD_MUTEX_INITIALIZER
};
void *writer(void *), *reader(void *);

int main(int argc, char **argv)
{
     int i, sum=0, nthreads, count[MAXNTHREADS];
     pthread_t tid_prod[MAXNTHREADS], tid_cons;

     nitems = MIN(atoi(argv[2]), MAXNITEMS);
     nthreads = MIN(atoi(argv[1]), MAXNTHREADS);
     printf("No. of Threads: %d\tNo. of Items: %d\n", shared.nput, nitems);
     for (i=0; i<nthreads; i++) {
          count[i] = 0;
          pthread_create(&tid_prod[i], NULL, writer, (void *)(&count[i]));
     }
     for (i=0; i<nthreads; i++) {
          pthread_join(tid_prod[i], NULL);
          printf("count[%d] = %d\n", i, count[i]);
          sum += count[i];
     }
     printf("Total:\t%d\n", sum);
     pthread_create(&tid_cons, NULL, reader, NULL);
     pthread_join(tid_cons, NULL);
     
     exit(0);
}
void *writer(void *arg)
{
     for ( ; ; ) {
          pthread_mutex_lock(&shared.mutex);
          if (shared.nput >= nitems) {
               pthread_mutex_unlock(&shared.mutex);
               return(NULL);
          }
          
          shared.buff[shared.nput] = shared.nval;
          ++shared.nput;
          ++shared.nval;

          pthread_mutex_unlock(&shared.mutex);
          *((int *) arg) += 1;
     }
}

void *reader(void *arg)
{
     int i;
     for (i=0; i<nitems; i++) {
          if (shared.buff[i] != i)
               printf("buff[%d] = %d\n", i, shared.buff[i]);
     }
     
     return(NULL);
}

