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

#define DATASIZE 100 * 1024 * 1024

long value;
unsigned char *data;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

/**
 * Compile with gcc -o e5 e5.c -lm -lpthread
 */

int compute_value(int start, int end)
{
  int value;
  for(int i=start; i < end; i++)
    value += (long)cos(sqrt((double)data[i]));
  return value;
}

void *run(int *tid)
{
  int ds = DATASIZE / 4;
  int start = ds * (*tid);
  int v = compute_value(start, start+ds);

  // Always try to do as much work as possible outside of the critical section:
  pthread_mutex_lock(&lock);
  value += v;
  pthread_mutex_unlock(&lock);
}

int main(int argc, char *argv[])
{
  pthread_t th[4];
  int tid[4] = {0, 1, 2, 3};
  /* Leave the following unmodified: */
  if (argc > 1) srand(atoi(argv[1]));
  value = 0;
  data = malloc(sizeof(unsigned char) * DATASIZE);

  printf("Generating data...\n");
  for(int i=0; i < DATASIZE; i++) {
    data[i] = (unsigned char)(rand() % 100);
  }

  /* Add thread support from here: */
  printf("Computing...\n");
  for(int i=0; i < 4; i++)
    pthread_create(&th[i], NULL, (void *)run, &tid[i]);
  for(int i=0; i < 4; i++)
    pthread_join(th[i], NULL);

  printf("%ld\n", value);
  return 0;
}
