Я пытаюсь написать простую программу пула потоков в pthread. Однако кажется, что pthread_cond_signal
не блокирует, что создает проблему. Например, скажем, у меня есть программа "производитель-потребитель":
pthread_cond_t my_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t my_cond_m = PTHREAD_MUTEX_INITIALIZER;
void * liberator(void * arg)
{
// XXX make sure he is ready to be freed
sleep(1);
pthread_mutex_lock(&my_cond_m);
pthread_cond_signal(&my_cond);
pthread_mutex_unlock(&my_cond_m);
return NULL;
}
int main()
{
pthread_t t1;
pthread_create(&t1, NULL, liberator, NULL);
// XXX Don't take too long to get ready. Otherwise I'll miss
// the wake up call forever
//sleep(3);
pthread_mutex_lock(&my_cond_m);
pthread_cond_wait(&my_cond, &my_cond_m);
pthread_mutex_unlock(&my_cond_m);
pthread_join(t1, NULL);
return 0;
}
Как описано в двух меток XXX
, если я уберу вызовы sleep
, тогда main()
может остановиться, потому что он пропустил пробуждение от liberator()
. Конечно, sleep
не очень надежный способ гарантировать, что.
В реальной ситуации это будет рабочий поток, сообщающий менеджерскому потоку, что он готов к работе, или поток менеджера, объявляющий, что новая работа доступна.
Как бы вы сделали это надежно в pthread?
Разработка
@Borealid ответ рода работ, но его объяснение проблемы может быть лучше. Я предлагаю всем, кто смотрит на этот вопрос, прочитать дискуссию в комментариях, чтобы понять, что происходит.
В частности, я сам поправлю свой ответ и пример кода следующим образом, чтобы сделать это более ясным. (Так как исходный ответ Borealid, в то время как скомпилированный и обработанный, меня сильно смутил)
// In main
pthread_mutex_lock(&my_cond_m);
// If the flag is not set, it means liberator has not
// been run yet. I'll wait for him through pthread signaling
// mechanism
// If it _is_ set, it means liberator has been run. I'll simply
// skip waiting since I've already synchronized. I don't need to
// use pthread signaling mechanism
if(!flag) pthread_cond_wait(&my_cond, &my_cond_m);
pthread_mutex_unlock(&my_cond_m);
// In liberator thread
pthread_mutex_lock(&my_cond_m);
// Signal anyone who sleeping. If no one is sleeping yet,
// they should check this flag which indicates I have already
// sent the signal. This is needed because pthread signals
// is not like a message queue -- a sent signal is lost if
// nobody waiting for a condition when it sent.
// You can think of this flag as a "persistent" signal
flag = 1;
pthread_cond_signal(&my_cond);
pthread_mutex_unlock(&my_cond_m);