Чтобы процитировать man страницу:
При использовании условных переменных всегда существует логический предикат, включающий общие переменные, связанные с каждым условным ожиданием, которое истинно, если поток должен продолжить. Могут возникнуть ложные пробуждения от функций pthread_cond_timedwait () или pthread_cond_wait (). Поскольку возврат из pthread_cond_timedwait () или pthread_cond_wait () ничего не подразумевает в значении этого предиката, предикат должен быть переоценен после такого возврата.
Таким образом, pthread_cond_wait
можете вернуться, даже если вы не сообщили об этом. По крайней мере, на первый взгляд это кажется довольно жестоким. Это было бы похоже на функцию, которая случайно вернула неправильное значение или вернула случайно, прежде чем она действительно достигла правильного оператора возврата. Это похоже на серьезную ошибку. Но тот факт, что они решили документировать это на странице руководства, а не исправлять это, похоже, указывает на то, что есть законная причина, по которой мы pthread_cond_wait
внезапно просыпаемся. Предположительно, есть что-то внутреннее в том, как это работает, что делает его таким, что с этим ничего не поделаешь. Вопрос в том, что.
Почему же pthread_cond_wait
вернуться поддельно? Почему он не может гарантировать, что проснется только тогда, когда на него правильно подали сигналы? Кто-нибудь может объяснить причину его ложного поведения?
pthread_cond_(timed)wait
: «Если сигнал доставлен ... поток возобновляет ожидание переменной условия, как если бы он был не прервано, или оно должно вернуть ноль из-за ложного пробуждения ". Другие функции блокировки указывают,EINTR
когда прервано сигналом (напримерread
) или требуется возобновить (напримерpthread_mutex_lock
). Так что, если бы не было других причин для ложного пробуждения,pthread_cond_wait
можно было бы определить, как любой из них.Ответы:
Следующее объяснение дано Дэвидом Р. Бутенхофом в «Программирование с помощью потоков POSIX» (стр. 80):
В следующем обсуждении comp.programming.threads он расширяет концепцию дизайна:
источник
Есть по крайней мере две вещи, которые может означать «ложное пробуждение»:
pthread_cond_wait
может вернуться из вызова, даже если не было выполнено ни одного вызоваpthread_call_signal
илиpthread_cond_broadcast
условия.pthread_cond_wait
возвратах, возвращается из-за вызоваpthread_cond_signal
илиpthread_cond_broadcast
, однако после повторного запроса мьютекса нижележащий предикат оказывается больше не истинным.Но последний случай может иметь место, даже если реализация переменной условия не допускает первый случай. Рассмотрим очередь потребителя производителя и три потока.
pthread_cond_wait
и блоками в вызове, ожидающем сигнал / трансляцию.Так как вам уже всегда нужно проверять предикат в цикле, не имеет значения, могут ли базовые переменные условия иметь другие виды ложных пробуждений.
источник
pthread_cond_signal/broadcast
и вы не сможете сделать это, пока мьютекс не будет разблокирован вызовомpthread_cond_wait
.Раздел «Многократное пробуждение по сигналу условия» в pthread_cond_signal содержит пример реализации pthread_cond_wait и pthread_cond_signal, который включает в себя ложные пробуждения.
источник
Хотя я не думаю, что это учитывалось во время проектирования, здесь есть реальная техническая причина: в сочетании с отменой потока существуют условия, при которых использование режима пробуждения «внезапно» может быть абсолютно необходимым, по крайней мере, если вы готовы наложить очень-очень сильные ограничения на то, какие стратегии реализации возможны.
Ключевая проблема заключается в том, что, если поток действует на отмену, в то время как заблокирован
pthread_cond_wait
, побочные эффекты должны быть такими, как если бы он не потреблял никакого сигнала для переменной условия. Однако трудно (и весьма ограниченно) убедиться, что вы еще не использовали сигнал, когда начинаете действовать на отмену, и на этом этапе может оказаться невозможным «повторно отправить» сигнал в переменную условия, поскольку вы можете быть в ситуации, когда вызывающаяpthread_cond_signal
сторона уже имеет право уничтожить кондвара и освободить память, в которой он находился.Пособие по ложному следу дает вам легкий выход. Вместо того, чтобы продолжать действовать при отмене, когда она прибывает, будучи заблокированной для переменной условия, если вы, возможно, уже использовали сигнал (или если вы хотите быть ленивым, несмотря ни на что), вы можете объявить, что вместо этого произошел ложный след, и вернуться с успехом. Это совсем не мешает операции отмены, потому что правильный вызывающий абонент просто воздействует на ожидающую отмену при следующем цикле и
pthread_cond_wait
повторном вызове.источник