Сообщение Re[9]: Гарантированы ли ложные пробуждения? от 21.07.2019 14:58
Изменено 21.07.2019 15:00 Ssd13
Re[9]: Гарантированы ли ложные пробуждения?
M>>>>>>Суть моего предыдущего поста была в том, что wait()/notify() изначально рассчитаны на такие сценарии, поэтому все это учитывают и работают, как заявлено.
σ>>>>>Нет, не работают. Автор книги подтвердил, что в ней это баг.
M>>>>А вот тут хочу подробнее. Ты утверждаешь, что если пойти на wait() в одном потоке, затем этот поток временно остановится, а другой добавит данные в очередь и сделает notify(), то после этого второй поток проснувшись уйдет в ожидание, оставив необработанными только что добавленные данные?
σ>>>Да. https://stackoverflow.com/questions/17984552/fine-grained-locking-queue-in-c
M>>Спасибо за ссылку. Посмотрел. В том примере действительно баг. Условная переменная работает как надо при наличии блокировки, которая гарантирует, что данные не изменятся без владения mutex'ом. В том примере, во-первых, на изменение очереди (головы и хвоста) используются два mutex, во-вторых, проверка наличия данных делается не атомарно (get_tail отпускает блокировку до сравнения с head). Поэтому, данный пример не работает. Однако, когда я писал свой Futex на основе linux futex (для lockfree очереди, где такая проверка наличия данных не отработает в принципе, потому что блокировок нет и данные могут меняться параллельно потребителем и производителем), он устанавливал флаг при notify и в результате wait в таком случае не заснул бы без повторного прохода по данным. Аналогичный механизм может быть и в std::conditional_variable, тогда wait() не отработает, при успевшем отработать notify() и бага не проявится (но это уже особенности реализации, а не стандарта).
M>>P.S. Там бага проявляется потому что wait()/notify() используют неправильно, так что если использовать единую блокировку, то гонки не будет и, таки,
M>>
A>Ну и слог — читать невозможно — не изложение мыслей, а сплошной поток сознания.
Возможно, потому что все привыкли к односложным ответам.
σ>>>>>Нет, не работают. Автор книги подтвердил, что в ней это баг.
M>>>>А вот тут хочу подробнее. Ты утверждаешь, что если пойти на wait() в одном потоке, затем этот поток временно остановится, а другой добавит данные в очередь и сделает notify(), то после этого второй поток проснувшись уйдет в ожидание, оставив необработанными только что добавленные данные?
σ>>>Да. https://stackoverflow.com/questions/17984552/fine-grained-locking-queue-in-c
M>>Спасибо за ссылку. Посмотрел. В том примере действительно баг. Условная переменная работает как надо при наличии блокировки, которая гарантирует, что данные не изменятся без владения mutex'ом. В том примере, во-первых, на изменение очереди (головы и хвоста) используются два mutex, во-вторых, проверка наличия данных делается не атомарно (get_tail отпускает блокировку до сравнения с head). Поэтому, данный пример не работает. Однако, когда я писал свой Futex на основе linux futex (для lockfree очереди, где такая проверка наличия данных не отработает в принципе, потому что блокировок нет и данные могут меняться параллельно потребителем и производителем), он устанавливал флаг при notify и в результате wait в таком случае не заснул бы без повторного прохода по данным. Аналогичный механизм может быть и в std::conditional_variable, тогда wait() не отработает, при успевшем отработать notify() и бага не проявится (но это уже особенности реализации, а не стандарта).
M>>P.S. Там бага проявляется потому что wait()/notify() используют неправильно, так что если использовать единую блокировку, то гонки не будет и, таки,
M>>
M>>Хотя, конечно, такая бага у Энтони Вильямса (если это действительно его бага, а не пример, как делать не надо) — это эпично.wait()/notify() изначально рассчитаны на такие сценарии, поэтому все это учитывают и работают, как заявлено.
A>Ну и слог — читать невозможно — не изложение мыслей, а сплошной поток сознания.
Возможно, потому что все привыкли к односложным ответам.
Re[9]: Гарантированы ли ложные пробуждения?
M>>>>>>Суть моего предыдущего поста была в том, что wait()/notify() изначально рассчитаны на такие сценарии, поэтому все это учитывают и работают, как заявлено.
σ>>>>>Нет, не работают. Автор книги подтвердил, что в ней это баг.
M>>>>А вот тут хочу подробнее. Ты утверждаешь, что если пойти на wait() в одном потоке, затем этот поток временно остановится, а другой добавит данные в очередь и сделает notify(), то после этого второй поток проснувшись уйдет в ожидание, оставив необработанными только что добавленные данные?
σ>>>Да. https://stackoverflow.com/questions/17984552/fine-grained-locking-queue-in-c
M>>Спасибо за ссылку. Посмотрел. В том примере действительно баг. Условная переменная работает как надо при наличии блокировки, которая гарантирует, что данные не изменятся без владения mutex'ом. В том примере, во-первых, на изменение очереди (головы и хвоста) используются два mutex, во-вторых, проверка наличия данных делается не атомарно (get_tail отпускает блокировку до сравнения с head). Поэтому, данный пример не работает. Однако, когда я писал свой Futex на основе linux futex (для lockfree очереди, где такая проверка наличия данных не отработает в принципе, потому что блокировок нет и данные могут меняться параллельно потребителем и производителем), он устанавливал флаг при notify и в результате wait в таком случае не заснул бы без повторного прохода по данным. Аналогичный механизм может быть и в std::conditional_variable, тогда wait() не отработает, при успевшем отработать notify() и бага не проявится (но это уже особенности реализации, а не стандарта).
M>>P.S. Там бага проявляется потому что wait()/notify() используют неправильно, так что если использовать единую блокировку, то гонки не будет и, таки,
M>>
A>Ну и слог — читать невозможно — не изложение мыслей, а сплошной поток сознания.
Возможно, потому что все привыкли к односложным ответам. Но, я учту.
σ>>>>>Нет, не работают. Автор книги подтвердил, что в ней это баг.
M>>>>А вот тут хочу подробнее. Ты утверждаешь, что если пойти на wait() в одном потоке, затем этот поток временно остановится, а другой добавит данные в очередь и сделает notify(), то после этого второй поток проснувшись уйдет в ожидание, оставив необработанными только что добавленные данные?
σ>>>Да. https://stackoverflow.com/questions/17984552/fine-grained-locking-queue-in-c
M>>Спасибо за ссылку. Посмотрел. В том примере действительно баг. Условная переменная работает как надо при наличии блокировки, которая гарантирует, что данные не изменятся без владения mutex'ом. В том примере, во-первых, на изменение очереди (головы и хвоста) используются два mutex, во-вторых, проверка наличия данных делается не атомарно (get_tail отпускает блокировку до сравнения с head). Поэтому, данный пример не работает. Однако, когда я писал свой Futex на основе linux futex (для lockfree очереди, где такая проверка наличия данных не отработает в принципе, потому что блокировок нет и данные могут меняться параллельно потребителем и производителем), он устанавливал флаг при notify и в результате wait в таком случае не заснул бы без повторного прохода по данным. Аналогичный механизм может быть и в std::conditional_variable, тогда wait() не отработает, при успевшем отработать notify() и бага не проявится (но это уже особенности реализации, а не стандарта).
M>>P.S. Там бага проявляется потому что wait()/notify() используют неправильно, так что если использовать единую блокировку, то гонки не будет и, таки,
M>>
M>>Хотя, конечно, такая бага у Энтони Вильямса (если это действительно его бага, а не пример, как делать не надо) — это эпично.wait()/notify() изначально рассчитаны на такие сценарии, поэтому все это учитывают и работают, как заявлено.
A>Ну и слог — читать невозможно — не изложение мыслей, а сплошной поток сознания.
Возможно, потому что все привыкли к односложным ответам. Но, я учту.