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

Сообщение Re[7]: Гарантированы ли ложные пробуждения? от 21.07.2019 3:12

Изменено 21.07.2019 3:15 Ssd13

Re[7]: Гарантированы ли ложные пробуждения?
M>>>>Суть моего предыдущего поста была в том, что wait()/notify() изначально рассчитаны на такие сценарии, поэтому все это учитывают и работают, как заявлено.
σ>>>Нет, не работают. Автор книги подтвердил, что в ней это баг.

M>>А вот тут хочу подробнее. Ты утверждаешь, что если пойти на wait() в одном потоке, затем этот поток временно остановится, а другой добавит данные в очередь и сделает notify(), то после этого второй поток проснувшись уйдет в ожидание, оставив необработанными только что добавленные данные?


σ>Да. https://stackoverflow.com/questions/17984552/fine-grained-locking-queue-in-c


Спасибо за ссылку. Посмотрел. В том примере действительно баг. Условная переменная работает как надо при наличии блокировки, которая гарантирует, что данные не изменятся без владения mutex'ом. В том примере, во-первых, на изменение очереди (головы и хвоста) используются два mutex, во-вторых, проверка наличия данных делается не атомарно (get_tail отпускает блокировку до сравнения с head). Поэтому, данный пример не работает. Однако, когда я писал свой Futex на основе linux futex (для lockfree очереди, где такая проверка наличия данных не отработает в принципе, потому что блокировок нет и данные могут меняться параллельно потребителем и производителем), он устанавливал флаг при notify и в результате wait в таком случае не заснул бы без повторного прохода по данным. Аналогичный механизм может быть и в std::conditional_variable, тогда wait() не отработает, при успевшем отработать notify() и бага не проявится (но это уже особенности реализации, а не стандарта).
Re[7]: Гарантированы ли ложные пробуждения?
M>>>>Суть моего предыдущего поста была в том, что wait()/notify() изначально рассчитаны на такие сценарии, поэтому все это учитывают и работают, как заявлено.
σ>>>Нет, не работают. Автор книги подтвердил, что в ней это баг.

M>>А вот тут хочу подробнее. Ты утверждаешь, что если пойти на wait() в одном потоке, затем этот поток временно остановится, а другой добавит данные в очередь и сделает notify(), то после этого второй поток проснувшись уйдет в ожидание, оставив необработанными только что добавленные данные?


σ>Да. https://stackoverflow.com/questions/17984552/fine-grained-locking-queue-in-c


Спасибо за ссылку. Посмотрел. В том примере действительно баг. Условная переменная работает как надо при наличии блокировки, которая гарантирует, что данные не изменятся без владения mutex'ом. В том примере, во-первых, на изменение очереди (головы и хвоста) используются два mutex, во-вторых, проверка наличия данных делается не атомарно (get_tail отпускает блокировку до сравнения с head). Поэтому, данный пример не работает. Однако, когда я писал свой Futex на основе linux futex (для lockfree очереди, где такая проверка наличия данных не отработает в принципе, потому что блокировок нет и данные могут меняться параллельно потребителем и производителем), он устанавливал флаг при notify и в результате wait в таком случае не заснул бы без повторного прохода по данным. Аналогичный механизм может быть и в std::conditional_variable, тогда wait() не отработает, при успевшем отработать notify() и бага не проявится (но это уже особенности реализации, а не стандарта).

P.S. Там бага проявляется потому что wait()/notify() используют неправильно, так что если использовать единую блокировку, то гонки не будет и, таки,

wait()/notify() изначально рассчитаны на такие сценарии, поэтому все это учитывают и работают, как заявлено.