开发者

pthread_exit and/or pthread_join causing Abort and SegFaults

开发者 https://www.devze.com 2022-12-22 13:20 出处:网络
The following code is a simple thread game, that switches between threads causing the timer to decrease.

The following code is a simple thread game, that switches between threads causing the timer to decrease.

It works fine for 3 threads, causes and Abort(core dumped) for 4 threads, and causes a seg fault for 5 or more threads.

Anyone have any idea why this might be happening?

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


See below on why you should not depend on volatile in pthreads. However, your specific problem is probably because you malloc your pthread array, based on the num_of_threads variable before you've actually set num_of_thread from argv[]:

pthread_t *threads = (pthread_t *)malloc (num_of_threads * sizeof (pthread_t));
thread_running = 0;
num_of_threads = atoi (args[1]);

So there's a very good chance you're writing beyond the end of the threads array. The num_of_threads variable will probably be zero on start-up which means you're not allocating what you think you are. Move the allocation to after the extraction of the arguments and that should fix it.


And now, for your viewing pleasure :-), my original rant on the unsafe use of volatile, which I still stand by.

Do not rely on volatile to protect your shared variables. The correct way to do this is with the pthread_mutex_blab_blah_blah calls.

Of particular note, examine this code segment:

if (can_check) {
   if (time_left <= 0) {
    break;
   }
   // URK!!
   can_check=0;

URK!! is the point where your current thread may be switched out and another run, leading to the possibility that two threads can be running a critical section of code.

My advice is to forget the can_check altogether and just protect all the shared variables with a mutex, something like (from memory):

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

Then put at file-level:

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

and, in main, before starting any other threads:

pthread_mutexattr_init (&mutexattr);
// Change attributes if needed.
pthread_mutex_init (&mutex, &mutex_attr);

// Then run all you other stuff here, make sure you've joined with all threads.

pthread_mutex_destroy (&mutex);

Oh yeah, although I haven't done it, you should also check the return codes for all those mutex calls. I'm not going to add that since it'll clog up the answer with unnecessary detail, but it's good practice.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号