Подтвердить что ты не робот

Зачем нужен цикл 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);
4b9b3361

Ответ 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, почему второе "если" неверно.