2009-03-09 4 views
9

я наткнулся на этом интересном пункт в Boost thread documentation сегодня:паразитное разблокирование в повышающей нити

void wait(boost::unique_lock<boost::mutex>& lock) 

...

Эффекты: Атомно вызов lock.unlock() и блокируют текущий поток , Нить будет разблокирована, когда будет сообщено об этом , для этого -> notify_one() или this-> notify_all(), или ложно. Когда нить разблокирована (для по любой причине), блокировка повторно активирована вызовом lock.lock() перед вызовом wait возвращает. Блокировка также восстанавливается путем вызова lock.lock(), если функция завершает исключение .

Так что меня интересует значение слова «spuriously». Почему поток должен быть разблокирован по ложным причинам? Что можно сделать, чтобы разрешить это?

ответ

10

This article by Anthony Williams особенно подробно.

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

Он также указывает на то, что вы не должны использовать timed_wait перегрузкам, которые принимают длительность, и вы должны вообще использовать версии, которые принимают предикат

Это ошибка новичка, и один это легко преодолеть простым правилом : всегда проверяйте свой предикат в цикле при ожидании с условием переменной. Более коварная ошибка появляется от timed_wait().

This article by Vladimir Prus также интересен.

Но почему нам нужно время цикла, мы не можем написать:

if (!something_happened) 
    c.wait(m); 

Мы не можем. И причина убийцы в том, что «wait» может вернуть без какого-либо вызова «уведомить». Это называется побочным пробуждением и явно разрешено POSIX. По существу, возврат из «wait» только указывает, что данные общего доступа могут быть изменены , так что данные должны быть снова .

Хорошо, так почему же это еще не исправлено? Первая причина в том, что никто не хочет , чтобы исправить это. Приобретенный вызов «wait» в петли очень желателен для нескольких других причин. Но эти причины требуют объяснений, а поддельные пробуждение - это молот, который можно нанести любому ученику первого курса без сбой.

+0

Похоже, мы находим те же страницы, что не совсем неожиданно :) –

+1

Да, это своего рода резюме моих исследований сегодня, когда я выяснил причину ужасной ошибки, которую я страдал. Документация по ускорению может быть более ясной в этом вопросе –

+1

Я нашел, что повышает всю систему для ожидания и уведомления - особенно в boost :: interprocess - очень неприятно. Я бы использовал его только в том случае, если вам нужно, чтобы он был кросс-платформенным и теперь выполнен. –

2

This blog post дает основание для Linux в отношении системного вызова futex, когда сигнал передается процессу. К сожалению, он ничего не объясняет (и действительно просит больше информации).

Wikipedia entry on spurious wakeups (который, по-видимому, представляет собой концепцию шириной посиума, кстати, не ограничиваясь этим) может вас заинтересовать.

+0

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