2009-07-16 6 views
44

Я изучаю условия pthread и ожидания. Насколько я могу сказать, типичный ожидающий поток, как это:Pthread и условия ожидания

pthread_mutex_lock(&m); 
while(!condition) 
    pthread_cond_wait(&cond, &m); 
// Thread stuff here 
pthread_mutex_unlock(&m); 

То, что я не могу понять, почему линия while(!condition) необходим, даже если я использую pthread_cond_signal(), чтобы разбудить нить.

Я понимаю, что если я использую pthread_cond_broadcast() мне нужно проверить состояние, потому что я просыпаюсь все ожидающих потоки, и один из них может сделать состояние ложного снова перед разблокировкой мьютекса (и, таким образом, передавая исполнение в другую просыпалси который не должен выполняться в этой точке). Но если я использую pthread_cond_signal(), я просыпаюсь только один нить, поэтому условие должно быть правдой. Таким образом, код может выглядеть так:

pthread_mutex_lock(&m); 
pthread_cond_wait(&cond, &m); 
// Thread stuff here 
pthread_mutex_unlock(&m); 

Я прочитал кое-что о паразитных сигналах, которые могут произойти. Это (и только это) причина? Почему у меня есть ложные синглы? Или чего-то еще я не получу?

Я предполагаю, что код сигнала, как это:

pthread_mutex_lock(&m); 
condition = true; 
pthread_cond_signal(&cond); // Should wake up *one* thread 
pthread_mutex_unlock(&m); 

ответ

43

Настоящая причина, по которой вы должны ставить pthread_cond_wait в цикле while не из-за ложного пробуждения. Даже если ваша переменная условия не имела ложного пробуждения, вам все равно понадобится цикл, чтобы поймать общий тип ошибки. Зачем? Рассмотрим, что может произойти, если несколько потоков ждать на том же состоянии:

Thread 1       Thread 2   Thread 3 
check condition (fails) 
(in cond_wait) unlock mutex 
(in cond_wait) wait 
           lock mutex 
           set condition 
           signal condvar 
           unlock mutex 
                lock mutex 
                check condition (succeeds) 
                do stuff 
                unset condition 
                unlock mutex 
(in cond_wait) wake up 
(in cond_wait) lock mutex 
<thread is awake, but condition 
is unset> 

Проблема здесь состоит в том, что поток должен освободить мьютекс перед ожиданием, потенциально позволяя другой поток «украсть» все, что нить ждет. Если не гарантируется, что только один поток может ждать этого условия, неверно предположить, что условие действительно, когда поток просыпается.

+1

точно. до-голосование. это должно привлечь больше внимания, чем принятый ответ. –

15

Предположим, что вы не проверить состояние. Затем, как правило, вы не можете избежать следующей плохо происходит (по крайней мере, вы не можете избежать его в одной строке кода):

Sender        Receiver 
locks mutex 
sets condition 
signals condvar, but nothing 
    is waiting so has no effect 
releases mutex 
            locks mutex 
            waits. Forever. 

Конечно ваш второй пример кода может избежать этого, выполнив:

Тогда, конечно, было бы так, что если бы не было только одного приемника, и если бы cond_signal были единственной вещью, которая могла бы разбудить ее, тогда она только когда-нибудь проснется, когда условие будет установлено и, следовательно, не нужен цикл. nos, почему второе «если» неверно.

+0

Я вижу, поэтому требуется «если» из-за логической причины (бесконечное ожидание), но на самом деле требуется некоторое время из-за проблем с реализацией (ложные сигналы). – Emiliano

+0

Да, когда я впервые использовал библиотеку pthreads, я задал тот же вопрос. Я пропустил проверку переменной состояния, и моя программа будет сигнализировать до того, как произойдет ожидание. Это целая точка функций ожидания/сигнала. Подождать и сигнализировать о некоторых изменениях в мьютексе в состоянии памяти. –