Информация об изменениях

Сообщение Re: C++11: Синхронизация - Условные переменные и ложные проб от 21.03.2019 21:17

Изменено 29.03.2019 6:57 netch80

Re: C++11: Синхронизация - Условные переменные и ложные проб
Здравствуйте, rsdn_179b, Вы писали:

_>Зачем крутиться в цикле и проверять какие-то условия


Futex, как некоторые коллеги пишут тут, ни при чём. Правило про возможность ложных пробуждений возникло задолго до Linux и futex. Оно было в BSD в select(). Оно было в изначальном pthreads (которые появились на SysV, как Solaris, и перенесены 1:1 в Java). Оно было в Bell Unix в ядерном sleep/wakeup (там вместо мьютексов были уровни приоритета ядра, но суть та же). Более того, этот механизм в таком виде существовал ещё до Unix, и там тоже было это правило.

Настоящая и исконная причина: в multi-producer-multi-customer построении невозможно гарантировать, что когда потребителю A "свистнули", что появился ресурс, не придёт потребитель B, который захватит мьютекс раньше и потребит ресурс. Когда же B отпустит мьютекс и A получит такую возможность, ему уже может не достаться ресурса, он увидит другое состояние, чем предполагалось на момент отдачи нотификации.

Частным "ракурсом" этой проблемы является ABA problem, но ситуация к ней сводится только в простых случаях (перед спячкой увидели какое-то состояние, вышли из спячки — а там вернулись к нему же; в сложных случаях состояние будет другое, хотя тоже неинтересное).

Если кто-то спросит, почему не делать такую синхронизацию, при которой нет такой проблемы... можно сделать. Например, при notifyOne() указывать, кого именно notify. Но тогда другая проблема — а что, если этот решил вообще выйти из игры? Ему надо переслать на кого-то другого? Увы, за >50 лет существования темы такой синхронизации — этот подход самый простой и надёжный.

А уже последствием описанной проблемы является возможность разрешения ложных пробуждений за счёт коллизий реализации (про futex — скорее сказка, а вот select collision в старых BSD была известным явлением).
Re: C++11: Синхронизация - Условные переменные и ложные проб
Здравствуйте, rsdn_179b, Вы писали:

_>Зачем крутиться в цикле и проверять какие-то условия


Futex, как некоторые коллеги пишут тут, ни при чём. Правило про возможность ложных пробуждений возникло задолго до Linux и futex. Оно было в BSD в select(). Оно было в изначальных версиях многониточности на Unix (которые появились на SysV, как Solaris), и перенесено 1:1 в Java. Оно было в Bell Unix в ядерном sleep/wakeup (там вместо мьютексов были уровни приоритета ядра, но суть та же). Более того, этот механизм в таком виде существовал ещё до Unix, и там тоже было это правило.

Настоящая и исконная причина: в multi-producer-multi-customer построении невозможно гарантировать, что когда потребителю A "свистнули", что появился ресурс, не придёт потребитель B, который захватит мьютекс раньше и потребит ресурс. Когда же B отпустит мьютекс и A получит такую возможность, ему уже может не достаться ресурса, он увидит другое состояние, чем предполагалось на момент отдачи нотификации.

Частным "ракурсом" этой проблемы является ABA problem, но ситуация к ней сводится только в простых случаях (перед спячкой увидели какое-то состояние, вышли из спячки — а там вернулись к нему же; в сложных случаях состояние будет другое, хотя тоже неинтересное).

Если кто-то спросит, почему не делать такую синхронизацию, при которой нет такой проблемы... можно сделать. Например, при notifyOne() указывать, кого именно notify. Но тогда другая проблема — а что, если этот решил вообще выйти из игры? Ему надо переслать на кого-то другого? Увы, за >50 лет существования темы такой синхронизации — этот подход самый простой и надёжный.

А уже последствием описанной проблемы является возможность разрешения ложных пробуждений за счёт коллизий реализации (про futex — скорее сказка, а вот select collision в старых BSD была известным явлением).