pthread_exit и / или pthread_join вызывают прерывания и SegFaults - PullRequest
0 голосов
/ 12 марта 2010

Следующий код представляет собой простую потоковую игру, которая переключается между потоками, вызывая уменьшение таймера.

Работает нормально для 3 потоков, вызывает и прерывает работу (сбрасывается ядро) для 4 потоков, вызывает ошибку сегмента для 5 или более потоков.

Кто-нибудь знает, почему это может происходить?

#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 Ответ

2 голосов
/ 12 марта 2010

Смотрите ниже о том, почему вы не должны зависеть от volatile в pthreads. Однако ваша специфическая проблема , вероятно, связана с тем, что вы неправильно размещаете свой массив pthread, основываясь на переменной num_of_threads до , которую вы фактически установили num_of_thread из 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);
}

Затем поместите на уровне файла:

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

и, в основном, перед запуском любых других потоков:

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

О да, хотя я этого не сделал, вам также следует проверить коды возврата для всех этих вызовов мьютекса. Я не собираюсь добавлять это, поскольку это забьет ответ ненужными подробностями, но это хорошая практика.

...