#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>

pthread_mutex_t reduction_mutex;
pthread_t *tid;
int n, num_threads;
double pi, w;
double f(a)
     double a;{ return (4.0 / (1.0 + a*a));}

void *PIworker(void *arg){
  int i, myid;
  double sum, mypi, x;
  /* set individual id to start at 0 */
  myid = pthread_self()-tid[0];
  myid = myid/-8392704; //for -8392704: printf("myid=%d\n",pthread_self()-tid[0]);
  /* integrate function */
  sum = 0.0;
  for (i=myid+1; i<=n; i+=num_threads) 
    {
      x = w*((double)i - 0.5);
      sum += f(x);
    }
  mypi = w*sum;
  /* reduce value */
  pthread_mutex_lock(&reduction_mutex);
  pi += mypi;
  pthread_mutex_unlock(&reduction_mutex);
  return(0);
}

int main(argc,argv)
     int argc;
     char *argv[];
{
  int i;
  double time_start, time_end; 
  struct timeval tv; 
  struct timezone tz; 
  /* get num intervals and num threads from command line */
  n = atoi(argv[1]);
  num_threads = atoi(argv[2]);
  gettimeofday(&tv, &tz); 
  time_start = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; 
  //
  w = 1.0 / (double) n;
  pi = 0.0;
  tid = (pthread_t *) calloc(num_threads, sizeof(pthread_t));
  /* initialize lock */
  if (pthread_mutex_init(&reduction_mutex, NULL))
    fprintf(stderr, "Cannot init lock\n"), exit(1);
  /* create the threads */
  for (i=0; i<num_threads; i++)
    if(pthread_create(&tid[i], NULL, PIworker, NULL))
      fprintf(stderr,"Cannot create thread %d\n",i), exit(1);
  /* join threads */
  for (i=0; i<num_threads; i++)
    pthread_join(tid[i], NULL);
  printf("computed pi = %.16f\n", pi);
  gettimeofday(&tv, &tz); 
  time_end = (double)tv.tv_sec +  (double)tv.tv_usec / 1000000.0; 
  printf("Elapsed Time=%lf sec. \n", time_end - time_start); 
  exit(0);
}
