Kevin Postlethwait
Kevin Postlethwait

Reputation: 1

First thread not running with given argument

int run_me(unsigned long prime, unsigned long max, int *ary) {
  unsigned long i;
  printf("\nI am %d", prime);

  if(prime > sqrt(max)) {
    return 1; /* do no run */
  }

  for(i = 3; i*prime < max; i+=2) {
    ary[i*prime - 1] = 1;
  }

  return 0;
}

typedef struct Args {
  unsigned long max, prime;
  int *ary;
} args;

void *thread_runner(void *all_args) {
  args *my_args = all_args;
  run_me(my_args->prime, my_args->max, my_args->ary);
  return 0;
}

unsigned long *sieve_of_eratosthenes(unsigned long begin, unsigned long end) {
  unsigned long i, j, arylen, *ary_to_ret;
  unsigned long current_primes[4] = {3, 5, 7, 11}; /* holds primes being used by threads*/
  int *ary_of_all;
  pthread_t threads[4];
  args *curr;

  curr = malloc(sizeof(args));

  ary_of_all = calloc(end, sizeof(int));
  arylen = end - begin + 2;
  ary_to_ret = calloc(arylen, sizeof(unsigned long));
  ary_of_all[0] = 1;

  /*mark all even numbers*/
  for(i = 1; 2 * i < end; i++) {
    ary_of_all[2*i - 1] = 1;
  }

  while(current_primes[3] < sqrt(end)) {
      /*run threads with current primes*/
    for(i = 0; i < 4; i++) {
      curr->prime = current_primes[i];
      curr->max = end;
      curr->ary = ary_of_all;
      pthread_create(&threads[i], NULL, thread_runner, curr);
    }
    /* join all threads */
    for(i = 0; i < 4; i++) {
      pthread_join(threads[i], NULL);
    }

    j = 0; /* number of primes found */

    /*find new primes*/
    for(i = current_primes[3] + 2; i < end && j < 4; i+=2) {
      if(ary_of_all[i - 1] == 0) {
        current_primes[j] = i;
        j++;
      }
    }

  }

  /*run threads one more time*/
  if(current_primes[0] <= sqrt(end)) {
    for(i = 0; i < 4; i++) {
      curr->prime = current_primes[i];
      curr->max = end;
      curr->ary = ary_of_all;
      pthread_create(&threads[i], NULL, thread_runner, curr);
    }
    /* join all threads */
    for(i = 0; i < 4; i++) {
      pthread_join(threads[i], NULL);
    }
  }

  /*create the array to be returned*/
  j = 0; /*pos in *ary_to_ret*/
  for(i = begin; i <= end; i++) {
    if(ary_of_all[i-1] == 0) {
      ary_to_ret[j] = i;
      j++;
    }

  }

  ary_to_ret[j] = 0; /* null terminate */
  ary_to_ret = realloc(ary_to_ret, (j+1) * sizeof(unsigned long));
  return ary_to_ret;
}

I am running the above code in order to get a list of primes given a high and low value using the Sieve of Eratosthenes. I have the code mostly working, however when I run this code the thread which I create using the first element in my curr_primes array is never used and instead runs 5, 7, 11, 11. It does this every time it runs through the array and repopulates it. I was wondering if someone could explain to me why it runs in this way.

Upvotes: 0

Views: 43

Answers (1)

kaylum
kaylum

Reputation: 14044

You are passing the same curr pointer to all the threads. You are lucky that it even works as well as you have observed as that is a huge race condition. Instead, the code needs to pass a seperate arg buffer to each thread. Here is one example:

/* doesn't really need to be dynamic memory in this simple example */
args curr[4];

for(i = 0; i < 4; i++) {
  curr[i].prime = current_primes[i];
  curr[i].max = end;
  curr[i].ary = ary_of_all;
  pthread_create(&threads[i], NULL, thread_runner, &curr[i]);
}

/* join all threads */
for(i = 0; i < 4; i++) {
  pthread_join(threads[i], NULL);
}

Upvotes: 1

Related Questions