HotShot51015
HotShot51015

Reputation: 31

How to tell what is causing seg fault when using pthread_create?

I'm having trouble finding the cause of this seg fault when calling pthread_create...

GDB is giving me Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7bc741d in pthread_create@@GLIBC_2.2.5 () from /lib64/libpthread.so.0

I'll include the part of the code that calls it and the part of the code which includes the function the threads are calling.

int main(int argc, char **argv)
{
  /*
   * Declare local variables
   */
  int i, j; // LK
  pthread_t *cat[NUM_CATS]; // LK
  pthread_t *lizard[NUM_LIZARDS]; // LK


  /*
   * Check for the debugging flag (-d)
   */
  debug = 0;
  if (argc > 1)
    if (strncmp(argv[1], "-d", 2) == 0)
      debug = 1;


  /*
   * Initialize variables
   */
  numCrossingSago2MonkeyGrass = 0;
  numCrossingMonkeyGrass2Sago = 0;
  running = 1;


  /*
   * Initialize random number generator
   */
  srandom( (unsigned int)time(NULL) );


  /*
   * Initialize locks and/or semaphores
   */

  sem_init(&driveway, 0, 20); // LK

  /*
   * Create NUM_LIZARDS lizard threads
   */

  // LK
  for(i = 0; i < NUM_LIZARDS; i++) {
    pthread_create(lizard[i], NULL, lizardThread, (void *)(&i));
  }

And the function called by pthread_create...

void * lizardThread( void * param )
{
  int num = *(int*)param;

  if (debug)
    {
      printf("[%2d] lizard is alive\n", num);
      fflush(stdout);
    }

  while(running)
    {

      lizard_sleep(num); // LK
      sago_2_monkeyGrass_is_safe(num); // LK
      cross_sago_2_monkeyGrass(num); // LK
      lizard_eat(num); // LK
      monkeyGrass_2_sago_is_safe(num); // LK
      cross_monkeyGrass_2_sago(num); // LK

    }

  pthread_exit(NULL);
}

Upvotes: 0

Views: 2059

Answers (2)

Some programmer dude
Some programmer dude

Reputation: 409196

You have the principle right, that you should pass a pointer to a pthread_t as the first argument to the pthread_create function.

The problem is that the pointers must actually point to something.

Normally when creating a single thread, you use a single pthread_t variable (not a pointer!) and uses the address-of operator when calling pthread_create. Like

pthread_t thread;  // Creates a normal non-pointer variable
pthread_create(&thread, ...);  // Pass the address of the variable, as a pointer to it

For your program you should do the same, pass pointers to actual pthread_t instances using the & operator. For this you first need to change the lizard array to not be an array of pointers:

pthread_t lizard[NUM_LIZARDS]; // LK

Then use the address-of operator when creating the threads:

pthread_create(&lizard[i], NULL, lizardThread, (void *)(&i));

By using the address-of operator & like this is emulating something called "call by reference".


There is however another problem in your code, that is much more subtle.

Because you pass a pointer to the loop variable i when the thread function actually starts the loop might have iterated a couple of times which means the value of i will not be correct when you dereference the pointer in the thread function. This is known as a data race or race condition.

The solution to this is to actually not pass a pointer, but the integer value itself. You do this by casting it to an intptr_t (which is big enough to hold both integers and pointers) and casting that to a pointer:

pthread_create(&lizard[i], NULL, lizardThread, (void *) (intptr_t) i);

The intptr_t type is part of the fixed-width integer types introduced in the C99 standard.

To use it you need to cast it back in the thread function:

int num = (int) (intptr_t) param;

Upvotes: 2

P.P
P.P

Reputation: 121397

The segfault is very likely because of passing uninitialized thread ID to pthread_create(). The array lizard isn't initialized.

Instead use an array:

  pthread_t lizard[NUM_LIZARDS]; // LK

  ...

  // LK
  for(i = 0; i < NUM_LIZARDS; i++) {
    pthread_create(&lizard[i], NULL, lizardThread, (void *)(&i));
  }

Also, note that there's data race since you pass &i to all threads. Instead you can use an array to fix the data race.

  int arr[NUM_LIZARDS];
  for(i = 0; i < NUM_LIZARDS; i++) {
    arr[i] = i;
    pthread_create(&lizard[i], NULL, lizardThread, &arr[i]);
  }

Upvotes: 4

Related Questions