Зачем нужен цикл while для условий ожидания pthread? - PullRequest
49 голосов
/ 16 июля 2009

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

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);

Ответы [ 2 ]

46 голосов
/ 27 января 2011

Реальная причина, по которой вы должны поместить 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>

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

16 голосов
/ 16 июля 2009

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

 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 описывает, почему второе «если» не соответствует действительности.

...