Вчера полдня бился, так и не разгадал загадку pthreads.
Итак, у меня есть основной поток, который проверяет, не было ли запроса на создание окна GLUT и опрашивает события окон посредством glutMainLoopEvent()
. Все бы хорошо, но чтобы другие потоки (которые могут изменять содержимое отображаемого изображения) имели возможность вклиниться между блокировкой/разблокировкой мьютекса, я вставляю паузу в 10мс. И вот в этой паузе и кроется проблема: при убивании этого основного потока с помощью pthread_cancel(GLUTthread)
и последующем ожидании смерти (pthread_join(GLUTthread, NULL)
) на pthread_join нет-нет, да происходит зависание. Я так понял, что pthread_cancel просто не срабатывает, если вызывается, когда поток находится в состоянии паузы.
Паузу реализовывал тремя способами. Сначала было просто
usleep(10000);
Потом сделал так:
struct timeval tv;
...
tv.tv_sec = 0;
tv.tv_usec = 10000;
select(0, NULL, NULL, NULL, &tv);
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;
struct timespec timeToWait;
struct timeval now;
while(1){
pthread_mutex_lock(&winini_mutex);
... // критическая секция
gettimeofday(&now,NULL);
timeToWait.tv_sec = now.tv_sec;
timeToWait.tv_nsec = now.tv_usec * 1000UL + 10000000UL;
pthread_cond_timedwait(&fakeCond, &winini_mutex, &timeToWait);
pthread_mutex_unlock(&winini_mutex);
... // некритическая секция
}
Как же с этим бороться?
Сейчас у меня пауза при помощи pthread_cond_timedwait, а еще я запихал в критическую секцию проверку
if(!initialized){
DBG("!initialized");
pthread_exit(NULL);
}
void clear_GL_context(){
FNAME();
if(!initialized) return;
DBG("lock");
pthread_mutex_lock(&winini_mutex);
initialized = 0;
DBG("locked");
// kill main GLUT thread
pthread_cancel(GLUTthread);
pthread_mutex_unlock(&winini_mutex);
forEachWindow(killwindow_v);
DBG("join");
pthread_join(GLUTthread, NULL);
pthread_mutex_unlock(&winini_mutex);
DBG("main GL thread cancelled");
}
Вот как правильно поступить?