Зачем нужен цикл while для условий ожидания pthread?
Я изучаю условия pthread и wait. Насколько я могу судить, типичный ожидающий поток выглядит так:
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);
Ответы
Ответ 1
Настоящая причина, по которой вы должны поставить 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>
Проблема заключается в том, что поток должен освобождать мьютекс перед ожиданием, потенциально позволяя другому потоку "украсть" все, что ожидает этот поток. Если не гарантируется, что только один поток может ждать этого условия, неверно предположить, что условие действительно, когда поток просыпается.
Ответ 2
Предположим, вы не проверяете условие. Тогда обычно вы не можете избежать следующих плохих событий (по крайней мере, вы не можете избежать этого в одной строке кода):
Sender Receiver
locks mutex
sets condition
signals condvar, but nothing
is waiting so has no effect
releases mutex
locks mutex
waits. Forever.
Конечно, ваш второй пример кода мог бы избежать этого:
pthread_mutex_lock(&m);
if (!condition) pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
Тогда, конечно, было бы, если бы существовал только один приемник, и если бы cond_signal
было единственным, что могло его разбудить, тогда он только когда-нибудь проснется, когда условие будет установлено, и, следовательно, не нужен цикл. nos, почему второе "если" неверно.