pthread_exit和/或pthread_join导致Abort和SegFaults

时间:2010-03-12 03:45:02

标签: c multithreading pthreads volatile

以下代码是一个简单的线程游戏,它在线程之间切换,导致计时器减少。

它适用于3个线程,原因和4个线程的Abort(核心转储),并导致5个或更多线程的seg错误。

任何人都知道为什么会发生这种情况?

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>

int volatile num_of_threads;
int volatile time_per_round;
int volatile time_left;
int volatile turn_id;
int volatile thread_running;
int volatile can_check;
void *  player (void * id_in){
 int id= (int)id_in;
 while(1){
  if(can_check){
   if (time_left<=0){
    break;
   }
   can_check=0;
   if(thread_running){
    if(turn_id==id-1){
     turn_id=random()%num_of_threads;
     time_left--;
    }
   }
   can_check=1;
  }
 }
 pthread_exit(NULL);
}
int main(int argc, char *args[]){
 int i;
 int buffer;
 pthread_t * threads =(pthread_t *)malloc(num_of_threads*sizeof(pthread_t));
 thread_running=0;
 num_of_threads=atoi(args[1]);
 can_check=0;
 time_per_round = atoi(args[2]);
 time_left=time_per_round;
 srandom(time(NULL));
 //Create Threads
 for (i=0;i<num_of_threads;i++){
  do{
  buffer=pthread_create(&threads[i],NULL,player,(void *)(i+1));
  }while(buffer == EAGAIN);
 }
 can_check=1;

 time_left=time_per_round;
 turn_id=random()%num_of_threads;
 thread_running=1;

 for (i=0;i<num_of_threads;i++){
  assert(!pthread_join(threads[i], NULL));
 }
 return 0;
}

1 个答案:

答案 0 :(得分:2)

请参阅下文,了解为什么不应该依赖volatile pthreads。但是,您的特定问题可能是因为您在之前基于num_of_threads变量对您的pthread数组进行了malloc实际设置num_of_thread来自{ {1}}:

argv[]

因此,非常很有可能在pthread_t *threads = (pthread_t *)malloc (num_of_threads * sizeof (pthread_t)); thread_running = 0; num_of_threads = atoi (args[1]); 数组的末尾之外写作。启动时threads变量可能为零,这意味着您没有分配您认为自己的内容。 在提取参数之后将分配移动到,并且应该修复它。


现在,为了您的观赏乐趣:-),我对num_of_threads的不安全使用的原始咆哮,我仍然支持。

依靠volatile来保护您的共享变量。正确的方法是使用volatile来电。

特别需要注意的是,请检查此代码段:

pthread_mutex_blab_blah_blah

if (can_check) { if (time_left <= 0) { break; } // URK!! can_check=0; 是当前线程可能被切换出来并且另一次运行的点,导致两个线程可能正在运行代码的关键部分。

我的建议是完全忘记URK!!并使用互斥锁保护所有共享变量,例如(来自内存):

can_check

然后放在文件级:

void *player (void * id_in) {
    int id = (int)id_in;
    while (1) {
        pthread_mutex_lock (&mutex);
        if (time_left <= 0) {
            pthread_mutex_unlock (&mutex);
            break;
        }
        if (thread_running) {
            if (turn_id == id-1) {
                turn_id = random() % num_of_threads;
                time_left--;
            }
        }
        pthread_mutex_unlock (&mutex);
    }
    pthread_exit(NULL);
}

并且,在main中,在开始任何其他线程之前:

pthread_mutexattr_t mutexattr;  // prob. not needed at file level.
pthread_mutex_t mutex;

哦,是的,虽然我没有这样做,但您还应该检查所有这些互斥锁调用的返回码。我不打算补充说,因为它会用不必要的细节堵塞答案,但这是很好的做法。