Ложное объяснение пробуждений звучит как ошибка, которую просто не стоит исправлять, верно?


30

Согласно статье в Википедии о ложных пробуждениях

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

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

«Ложные пробуждения могут показаться странными, но в некоторых многопроцессорных системах обеспечение полного предсказания пробуждения условия может существенно замедлить все операции с переменными состояния»

Звучит как ошибка, которую просто не стоит исправлять, верно?


1
связанные: «Почему у pthread_cond_wait есть ложные пробуждения?», stackoverflow.com/questions/8594591/…
Флориан Кастеллан

Ответы:


39

TL; DR Предположение («контракт») о ложных пробуждениях - это разумное архитектурное решение, принятое для обеспечения реально надежных реализаций потокового планировщика.

«Производственные соображения» здесь не имеют значения, это просто недоразумение, которое стало широко распространенным из-за того, что указано в опубликованной авторитетной ссылке. (авторитетные ссылки могут иметь ошибки, знаете, просто спросите Галилео Галилея ) В статье в Википедии содержится ссылка на цитируемую вами заметку только потому, что она полностью соответствует их формальным правилам цитирования опубликованной ссылки.

Гораздо более веская причина для введения концепции ложных пробуждений приведена в этом ответе SO, который основан на дополнительных деталях, представленных в (более старой версии) той же статьи:

В статье Википедии о ложных пробуждениях есть такой лакомый кусочек:

pthread_cond_wait()Функция в Linux осуществляется с помощью futexсистемного вызова. Каждый блокирующий системный вызов в Linux внезапно завершается, EINTRкогда процесс получает сигнал. ... pthread_cond_wait()не может перезапустить ожидание, потому что оно может пропустить реальное пробуждение за то короткое время, которое было за пределами futexсистемного вызова ...

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

Теперь, как планировщик мог восстановиться, учитывая, что во время отключения он мог пропустить некоторые сигналы, предназначенные для уведомления ожидающих потоков? Если планировщик ничего не делает, упомянутые «неудачные» потоки будут просто зависать, ожидая вечно - чтобы избежать этого, планировщик просто отправит сигнал всем ожидающим потокам.

Это делает необходимым заключение «контракта» о том, что ожидающий поток может быть уведомлен без причины. Чтобы быть точным, была бы причина - отключение планировщика - но поскольку поток спроектирован (по уважительной причине), чтобы не обращать внимания на внутренние детали реализации планировщика, эту причину, вероятно, лучше представить как «ложную».


С точки зрения нити это несколько напоминает закон Постеля (он же принцип устойчивости ),

быть консервативным в том, что вы делаете, быть либеральным в том, что вы принимаете от других

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


10
Тьфу ... закон Постела ... причина, по которой HTML и все виды веб-технологий так много дерьма в них (например, принятие HTML неправильного вложения тегов). Это в стороне, хороший ответ.
Томас Эдинг

3
Закон Постеля заключается в том, что многие ошибки остаются неисследованными годами, потому что, эй, даже если ваша функция возвращает неправильный вывод, приложение все равно работает! Лучшее изобретение когда-либо.
Pacerier

2
@Pacerier: функция, возвращающая неправильный вывод, не подчиняется закону Постеля (консервативная часть).
YvesgereY

@Pacerier: OTOH, требование к другим компонентам быть строгими, чтобы ошибки могли быть обнаружены раньше, является интересной позицией, ошибкой которой является сторона принципа «Fail Fast» и «договорного» дизайна.
YvesgereY

1

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

Одна обработка для двух проблем, которые я суммирую следующим:

Ложное пробуждение: ожидание потока запланировано до того, как условие будет установлено.
Принудительное засыпание: ожидание потока запланировано после того, как условие было снова подделано.

Поскольку позднее может произойти, некоторые зашли настолько далеко, что включили в контракт ложное пробуждение:

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

ТАК ссылка


Я хотел бы +1 это, но за идею, что кто-то преднамеренно ввел ложные пробуждения, чтобы заставить вызывающих абонентов добавлять циклы предикатов для решения проблемы вынужденных просыпаний. Я считаю это невероятным.
Руах

«Цель заключалась в том, чтобы заставить корректный / надежный код, требуя циклов предикатов». Смотрите предоставленную ссылку.
YvesgereY
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.