使用pthread_create时如何判断导致seg错误的原因?

时间:2016-10-19 16:13:01

标签: c multithreading segmentation-fault pthreads

调用pthread_create时,我无法找到这个seg错误的原因...

GDB正在给我Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7bc741d in pthread_create@@GLIBC_2.2.5 () from /lib64/libpthread.so.0

我将包含调用它的代码部分以及包含线程正在调用的函数的代码部分。

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));
  }

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);
}

2 个答案:

答案 0 :(得分:3)

由于将未初始化的线程ID传递给pthread_create(),因此非常容易发生段错误。数组lizard未初始化。

而是使用数组:

  pthread_t lizard[NUM_LIZARDS]; // LK

  ...

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

此外,请注意,因为您将&i传递给所有线程,所以有data race。相反,您可以使用数组来修复数据竞争。

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

答案 1 :(得分:2)

你有正确的原则,你应该将指针传递给pthread_t作为pthread_create函数的第一个参数。

问题是指针实际上必须指向

通常在创建单个线程时,使用单个pthread_t变量(不是指针!)并在调用pthread_create时使用address-of运算符。像

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

对于您的程序,您应该这样做,使用pthread_t运算符传递指向实际&实例的指针。为此,您首先需要将lizard数组更改为不是指针数组:

pthread_t lizard[NUM_LIZARDS]; // LK

然后在创建线程时使用address-of运算符:

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

通过使用地址运算符&,这样就可以模仿一些名为&#34;通过引用调用&#34;。

然而,您的代码中存在另一个问题,即更加微妙。

因为当线程函数实际启动时传递指向循环变量i的指针,循环可能已经迭代了几次,这意味着当你取消引用时,i的值将不正确线程函数中的指针。这称为数据竞争竞争条件

对此的解决方案是实际上传递指针,而是整数值本身。你可以通过将其转换为intptr_t(大到足以容纳整数和指针)并将其转换为指针来完成此操作:

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

intptr_t类型是C99标准中引入的the fixed-width integer types的一部分。

要使用它,您需要将其强制转换为线程函数:

int num = (int) (intptr_t) param;