Смотрите ниже о том, почему вы не должны зависеть от 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);
О да, хотя я этого не сделал, вам также следует проверить коды возврата для всех этих вызовов мьютекса. Я не собираюсь добавлять это, поскольку это забьет ответ ненужными подробностями, но это хорошая практика.