Общее правило при работе с потоками, не специфичное для С или pthreads: состояние резделяемое между потоками должно быть или атомарным или должно быть защищено примитивом синхронизации.
Код функции thread_process никак не гарантирует, что компилятор не выкинет проверку
!quit
, потому что quit не меняется в этой функции и в функциях вызываемых из неё.
Учитывая, что атомарность и потоки вошли в стандарт С11 имеет смысл смотреть туда.
Если С11 недоступен, смотреть в pthread_mutex_*, pthread_cond_*, ...
Может стоит вынести флаг в параметры потока
По-хорошему -- да, стоит. Это, однако, ортогонально к синхронизации доступа.
while(!quit) {
if(difftime(time(NULL), last_cycle) > 30) {
last_cycle = time(NULL);
// Тут мои грязные дела
}
}
Вместо busy wait лучше использовать
sleep
или что-нибудь типа
pthread_mutex_timedlock
/
pthread_cond_timedwait
.
Я бы оформил код этого примера так:#include <sys/time.h>
#include <pthread.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
struct thread1 {
pthread_mutex_t lock;
pthread_cond_t cond;
bool quit;
};
static void* thread_process(void *p) {
struct thread1 *arg = p;
for (;;) {
bool quit;
pthread_mutex_lock(&arg->lock);
if (!arg->quit) {
struct timeval now;
struct timespec ts;
gettimeofday(&now, NULL);
ts.tv_sec = now.tv_sec + 30;
ts.tv_nsec = now.tv_usec * 1000;
pthread_cond_timedwait(&arg->cond, &arg->lock, &ts);
}
quit = arg->quit;
pthread_mutex_unlock(&arg->lock);
if (quit)
return NULL;
// Тут мои грязные дела
}
return NULL;
}
int main() {
pthread_t th;
struct thread1 arg = {
.lock = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
.quit = false,
};
pthread_create(&th, NULL, thread_process, &arg);
char cmd[16];
while(true) {
scanf("%s", cmd);
if(!strcmp(cmd, "quit")) {
pthread_mutex_lock(&arg.lock);
arg.quit = true;
pthread_cond_broadcast(&arg.cond);
pthread_mutex_unlock(&arg.lock);
break;
}
// остальные команды
}
pthread_join(th, NULL);
return 0;
}