Сообщение Re: C++11: Синхронизация - Условные переменные и ложные проб от 21.03.2019 21:17
Изменено 21.03.2019 21:48 netch80
Re: C++11: Синхронизация - Условные переменные и ложные пробужде
Здравствуйте, rsdn_179b, Вы писали:
_>Зачем крутиться в цикле и проверять какие-то условия
Futex, как некоторые коллеги пишут тут, ни при чём. Правило про возможность ложных пробуждений возникло задолго до Linux и futex. Оно было в BSD в select(). Оно было в изначальном pthreads (которые появились на SysV, как Solaris, и перенесены 1:1 d Java). Оно было в Bell Unix в ядерном sleep/wakeup (там вместо мьютексов были уровни приоритета ядра, но суть та же). Более того, этот механизм в таком виде существовал ещё до Unix, и там тоже было это правило.
Настоящая и исконная причина: в multi-producer-multi-customer построении невозможно гарантировать, что когда потребителю A "свистнули", что появился ресурс, не придёт потребитель B, который захватит мьютекс раньше и потребит ресурс. Когда же B отпустит мьютекс и A получит такую возможность, ему уже может не достаться ресурса, он увидит другое состояние, чем предполагалось на момент отдачи нотификации.
Частным "ракурсом" этой проблемы является ABA problem, но ситуация к ней сводится только в простых случаях (перед спячкой увидели какое-то состояние, вышли из спячки — а там вернулись к нему же; в сложных случаях состояние будет другое, хотя тоже неинтересное).
Если кто-то спросит, почему не делать такую синхронизацию, при которой нет такой проблемы... можно сделать. Например, при notifyOne() указывать, кого именно notify. Но тогда другая проблема — а что, если этот решил вообще выйти из игры? Ему надо переслать на кого-то другого? Увы, за >50 лет существования темы такой синхронизации — этот подход самый простой и надёжный.
А уже последствием описанной проблемы является возможность разрешения ложных пробуждений за счёт коллизий реализации, как тут рассказали про futex.
_>Зачем крутиться в цикле и проверять какие-то условия
Futex, как некоторые коллеги пишут тут, ни при чём. Правило про возможность ложных пробуждений возникло задолго до Linux и futex. Оно было в BSD в select(). Оно было в изначальном pthreads (которые появились на SysV, как Solaris, и перенесены 1:1 d Java). Оно было в Bell Unix в ядерном sleep/wakeup (там вместо мьютексов были уровни приоритета ядра, но суть та же). Более того, этот механизм в таком виде существовал ещё до Unix, и там тоже было это правило.
Настоящая и исконная причина: в multi-producer-multi-customer построении невозможно гарантировать, что когда потребителю A "свистнули", что появился ресурс, не придёт потребитель B, который захватит мьютекс раньше и потребит ресурс. Когда же B отпустит мьютекс и A получит такую возможность, ему уже может не достаться ресурса, он увидит другое состояние, чем предполагалось на момент отдачи нотификации.
Частным "ракурсом" этой проблемы является ABA problem, но ситуация к ней сводится только в простых случаях (перед спячкой увидели какое-то состояние, вышли из спячки — а там вернулись к нему же; в сложных случаях состояние будет другое, хотя тоже неинтересное).
Если кто-то спросит, почему не делать такую синхронизацию, при которой нет такой проблемы... можно сделать. Например, при notifyOne() указывать, кого именно notify. Но тогда другая проблема — а что, если этот решил вообще выйти из игры? Ему надо переслать на кого-то другого? Увы, за >50 лет существования темы такой синхронизации — этот подход самый простой и надёжный.
А уже последствием описанной проблемы является возможность разрешения ложных пробуждений за счёт коллизий реализации, как тут рассказали про futex.
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 была известным явлением).
_>Зачем крутиться в цикле и проверять какие-то условия
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 была известным явлением).