Почему pthread_cond_wait имеет ложные пробуждения? - PullRequest
130 голосов
/ 21 декабря 2011

Цитировать справочную страницу:

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

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

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

Ответы [ 3 ]

95 голосов
/ 21 декабря 2011

Существует как минимум две вещи, которые может означать «ложное пробуждение»:

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

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

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

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

73 голосов
/ 21 декабря 2011

Следующее объяснение дано Дэвидом Р. Бутенхофом в «Программирование с помощью потоков 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. 
/------------------[ David.Buten...@compaq.com ]------------------\ 
| 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 ]-----/ 

7 голосов
/ 17 июля 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...