Home > Back-end >  multi threaded program - core dumped
multi threaded program - core dumped

Time:05-23

I'm trying to make a multi-threaded prime numbers counter program. I've added the critical codes for the understanding (the parseargs function works great in another program and feels unnecessary and I don't want to overload you with code).

Long story short, the program compile and work well with small numbers (up to 1000 max val and 8 threads), but when I'm trying to go with bigger numbers I keep getting a lot of errors like:

segmentation fault: core dumped, Floating point exception, realloc(): invalid next size.

What's wrong with the code? I know that I should use fewer global variables but I'm trying to make it work and then I will make cleaner and better. And the only place that I'm using realloc is inside of isprime; that works great in my other programs. What's the problem there?

        #include <ctype.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <math.h>
        #include <unistd.h>
        #include <pthread.h>
        #include <sys/mman.h>
        
        void parseargs(char *argv[], int argc, int *lval, int *uval, int *nval, int *tval);
        int isprime(int n);
        void setFlags();
        
        pthread_mutex_t num_lock;
        pthread_mutex_t count_lock;
        
        char *flagarr = NULL;
        int num;
        int lval = 1;//min value
        int uval = 100;//max value
        int count = 0;//primes counter
        
        int main (int argc, char **argv)
        {
          int nval = 10;// how much numbers to print
          int tval = 4;// threads number
          num = lval;
          
            if (pthread_mutex_init(&num_lock, NULL) != 0) {
                printf("\n mutex init has failed\n");
                return 1;
            } 
               if (pthread_mutex_init(&count_lock, NULL) != 0) {
                printf("\n mutex init has failed\n");
                return 1;
            }
        
          // Parse arguments
          parseargs(argv, argc, &lval, &uval, &nval, &tval);// works 100% (change the defult starting vals)
          if (uval < lval)
          {
            fprintf(stderr, "Upper bound should not be smaller then lower bound\n");
            exit(1);
          }    
          if (lval < 2)
          {
            lval = 2;
            uval = (uval > 1) ? uval : 1;
          }
          if (tval<1)
            tval=4;
        
          // Allocate flags
          flagarr= (char *)malloc(sizeof(char) * (uval-lval 1));
          if (flagarr == NULL)
            exit(1);
            
             //Allocate threads
          pthread_t* t = (pthread_t *)malloc(sizeof(pthread_t)*tval);
             if (t == NULL)
              exit(1);
              
         //start threads
          for(int i =0; i<tval ; i  ){
             printf("%d\n",i);
             pthread_create(&t[i],NULL,(void*)setFlags,NULL);
             }
             
         for(int i =0; i<tval ; i  )
             pthread_join(t[i],NULL);
        
        
        
          // Print results
          nval=count;
          printf("Found %d primes from %d to %d%c", count, lval,uval , count ? ' ' : '.');
          if(count && nval>0)
            printf("and printing the first %d of them:\n",nval);
          else
            printf("\n");
          for (num = lval; (num <= uval) && (nval) ; num  )
            if (flagarr[num - lval])
            {
              nval--;
              count--;
              printf("%d%c", num, (count && nval) ? ',' : '\n');  
            }
            free(flagarr);
            free(t);
              return 0;
        }
        
        void setFlags()
        {
         int myNum;
          for (; num <= uval;)
          { 
                pthread_mutex_lock(&num_lock);
                myNum=num;
                num  ;
                pthread_mutex_unlock(&num_lock);
                
            if (isprime(myNum))
            {
              flagarr[myNum - lval] = 1; 
              pthread_mutex_lock(&count_lock);
              count   ;
                pthread_mutex_unlock(&count_lock);
            } else {
              flagarr[myNum - lval] = 0; 
            }
          }
        }
int isprime(int n)
{
  static int *primes = NULL;    // NOTE: static !
  static int size = 0;      // NOTE: static !
  static int maxprime;      // NOTE: static !
  int root;
  int i;

  // Init primes array (executed on first call)
   pthread_mutex_lock(&first_lock);
  if (primes == NULL)
  {
    primes = (int *)malloc(2*sizeof(int));
    if (primes == NULL)
      exit(1);
    size = 2;
    primes[0] = 2;
    primes[1] = 3;
    maxprime = 3;
  }
  pthread_mutex_unlock(&first_lock);

  root = (int)(sqrt(n));

  // Update primes array, if needed
  while (root > maxprime)
    for (i = maxprime   2 ;  ; i =2)
      if (isprime(i))
      {
         pthread_mutex_lock(&primeFunc_lock);
        size  ;
        primes = (int *)realloc(primes, size * sizeof(int));
        if (primes == NULL)
          exit(1);
        primes[size-1] = i;
        maxprime = i;
        pthread_mutex_unlock(&primeFunc_lock);
        break;
      }

  // Check 'special' cases
  if (n <= 0)
    return -1;
  if (n == 1)
    return 0;

  // Check prime
  for (i = 0 ; ((i < size) && (root >= primes[i])) ; i  )
    if ((n % primes[i]) == 0)
      return 0;
  return 1;
}

CodePudding user response:

I know that I should use fewer global variables but I'm trying to make it work and then I will make cleaner and better.

For multithreaded programs this approach doesn't work -- you can't write a buggy program first, and make it pretty and bug-free later -- you have to get it bug-free first.

Also, global and static variables and threads generally don't mix.

Now, as others have noted, you access static variables in isprime() without any locks. Think about what would happen when thread T1 executes this code:

  for (i = 0 ; ((i < size) && (root >= primes[i])) ; i  )
    if ((n % primes[i]) == 0)

and another thread T2 executes this statement at the same time:

        primes = (int *)realloc(primes, size * sizeof(int));

Since primes is not an atomic variable, the compiler will (likely) load the value of primes into some register, and continue using that value through the entire loop in T1. The loop will be totally oblivious to the fact that primes may have already been free()d and realloc()ed in T2, and now points to entirely different memory block. T1 will continue reading the old (now dangling) memory.

Similar problems exist throughout your isprimes() function, and easily explain your observed crashes.

If you are on a Linux system, Thread sanitizer (and Address sanitizer) are your friends.

  • Related