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

Почему у pthread_cond_wait есть побочные пробуждения?

Чтобы процитировать страницу руководства:

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

Итак, pthread_cond_wait может вернуться, даже если вы его не указали. На первый взгляд, по крайней мере, это кажется довольно жестоким. Это было бы похоже на функцию, которая случайно возвращала неправильное значение или случайно возвращалась до того, как она действительно достигла правильного оператора return. Это похоже на серьезную ошибку. Но тот факт, что они решили записать это на странице руководства, а не исправить, как представляется, указывает на то, что существует законная причина, по которой pthread_cond_wait заканчивается просыпаясь ложно. Предположительно, есть что-то внутреннее о том, как это работает, что делает его таким, что это невозможно. Вопрос в том, что.

Почему pthread_cond_wait возвращает ложно? Почему он не может гарантировать, что он только проснется, когда он будет правильно сигнализирован? Может ли кто-нибудь объяснить причину своего ложного поведения?

4b9b3361

Ответ 1

Следующее объяснение дано Дэвидом Р. Бутенхофом в "Программирование с потоками POSIX" (стр. 80):

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

В следующем обсуждении comp.programming.threads он расширяет мышление, стоящее за дизайном:

Patrick Doyle wrote: 
> In article , Tom Payne   wrote: 
> >Kaz Kylheku  wrote: 
> >: It is so because implementations can sometimes not avoid inserting 
> >: these spurious wakeups; it might be costly to prevent them. 

> >But why?  Why is this so difficult?  For example, are we talking about 
> >situations where a wait times out just as a signal arrives? 

> You know, I wonder if the designers of pthreads used logic like this: 
> users of condition variables have to check the condition on exit anyway, 
> so we will not be placing any additional burden on them if we allow 
> spurious wakeups; and since it is conceivable that allowing spurious 
> wakeups could make an implementation faster, it can only help if we 
> allow them. 

> They may not have had any particular implementation in mind. 

You're actually not far off at all, except you didn't push it far enough. 

The intent was to force correct/robust code by requiring predicate loops. This was 
driven by the provably correct academic contingent among the "core threadies" in 
the working group, though I don't think anyone really disagreed with the intent 
once they understood what it meant. 

We followed that intent with several levels of justification. The first was that 
"religiously" using a loop protects the application against its own imperfect 
coding practices. The second was that it wasn't difficult to abstractly imagine 
machines and implementation code that could exploit this requirement to improve 
the performance of average condition wait operations through optimizing the 
synchronization mechanisms. 
/------------------[ [email protected] ]------------------\ 
| Compaq Computer Corporation              POSIX Thread Architect | 
|     My book: http://www.awl.com/cseng/titles/0-201-63392-2/     | 
\-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/ 

Ответ 2

Есть, по крайней мере, две вещи: "ложное пробуждение" может означать:

  • Нить, заблокированная в pthread_cond_wait, может вернуться из вызова, даже если вызов не был вызван или передан при условии.
  • Поток, заблокированный в pthread_cond_wait, возвращается из-за вызова сигнала или трансляции, однако после повторного поиска мьютекса найденный ниже предикат уже не является истинным.

Но последний случай может произойти, даже если реализация переменной условия не позволяет использовать первый случай. Рассмотрим очередь производителей и три потока.

  • Thread 1 только что выделил элемент и выпустил мьютекс, и очередь теперь пуста. Нить делает то, что делает с элементом, который он приобрел на каком-то процессоре.
  • Thread 2 пытается удалить объект из очереди, но обнаруживает, что очередь пуста, когда она проверена под мьютексом, вызывает pthread_cond_wait и блокирует вызов, ожидающий сигнал/трансляцию.
  • Тема 3 получает мьютекс, вставляет новый элемент в очередь, уведомляет переменную условия и освобождает блокировку.
  • В ответ на уведомление из потока 3 запланирован запуск потока 2, ожидающего условия.
  • Однако, прежде чем нить 2 справится с тем, чтобы попасть на CPU и захватить блокировку очереди, поток 1 завершает свою текущую задачу и возвращается в очередь для большей работы. Он получает блокировку очереди, проверяет предикат и обнаруживает, что в очереди есть работа. Он переходит к деактивации элемента, который вставил поток 3, освобождает блокировку и делает все, что он делает, с элементом, который помечен нитью.
  • Thread 2 теперь получает процессор и получает блокировку, но когда он проверяет предикат, он обнаруживает, что очередь пуста. Тема 1 "украсть" предмет, поэтому пробуждение кажется ложным. Поток 2 должен снова ждать состояния.

Итак, поскольку вам уже всегда нужно проверять предикат в цикле, не имеет значения, могут ли базовые переменные условия иметь другие виды побочных пробуждений.

Ответ 3

Раздел "Несколько пробуждений по сигналу состояния" в pthread_cond_signal имеет пример реализации pthread_cond_wait и pthread_cond_signal, который включает в себя ложные wakekups.