вторник, 27 апреля 2010 г.

Pthread Condition Variables и Windows Events (Креатив)

Материал взят из http://mejedi.livejournal.com/27180.html

Две такие похожие истории...

* Condition Variables
Жили-были процессы и была у них на всех одна открывашка. Когда процесс хочет выпить пива, он хватает открывашку. Если после этого процесс обнаруживает, что открывать ему нечего, он скрепя сердце возвращает открывашку и встает в одну из очередей.

Иногда приходит добрый дядька с пивом. Если в очереди никого нет, он тут же уходит.

1. pthread_cond_signal()
Приходит добрый дядька, приносит первому процессу в очереди бутылку пива и уходит. Процесс бежит хватать открывашку.

2. pthread_cond_broadcast()
Приходит добрый дядька, приносит всем процессам в очереди по пиву, и уходит. Процессы наперегонки бегут хватать открывашку.

Бывает так, что процессу не нравится полученное пиво. Тогда он снова встает в очередь.

* Events
Жили были процессы и была у каждого своя открывашка. Когда процессы хотят выпить пива, они выстраиваются в очереди. Очередь обслуживают двое дядек с очень разными характерами – Manual Reset Дядько и Auto Reset Дядько.

M.R. Дядько очень терпеливый. Он выдает всем стояльцем в очереди по пиву, и ждет чтобы кто-нибудь пришел еще. Всем новоприбывшим Дядько тоже дает пиво. Если управляющий не отзовет дядьку, он так и будет бесконечно всем давать пиво.

A.R. Дядько тоже терпеливый. Если он пришел – а в очереди никого, он подождет. С собой у Дядько только одна бутылка, поэтому он уйдет как только отдаст её первому процессу в очереди.

1. SetEvent()
Позвать дядьку.

2. ResetEvent()
Прогнать дядьку.

3. PulseEvent()
Управляющей звонит дядьке и говорит чтобы он принес пива. Потом перзванивает, и говорит что передумал. Потом звонит снова и говорит что пиво всё-таки надо нести. И так много раз. Дядька может сойти с ума и всех поубивать.


Между ними нет ничего общего. Auto Reset Event и pthread_cond_signal() ничем не похожи. Manual Reset Event не имеет никакого отношения к бродкастам. Отличия в самой модели. Pthread Condition Variables мгновенны, а Windows Events инерционны.

Когда сигналится condition variable, создается мгновенный и актуальный список ожидающих на c/v процессов. Далее пробуждаются или все процессы или только первый. Из-за этой мгновенности c/v всегда используется только вместе с мьютексом, чтобы не прозевать событие, которое сигналится с помощью c/v.

Семантика такова – pthread_cond_wait() принимает указатель на c/v и залоченный мьютекс. Затем атомарно разлочивается мьютекс и процесс ждет пока c/v не будет просигналена. Наконец мьютекс захватывается снова, и pthread_cond_wait() завершается. Предполагается, что если c/v просигналена пока процесс держит мьютекс, это можно безопасно проигнорировать. Обычно это на самом деле так, потому что используется мьютекс, который защищает структуру данных, изменение состояния которой сигналится с помощью c/v. Если мы взяли мьютекс, то можем спокойно проверить данные на предмет соответствия интересующему нас состоянию. Классический пример – защищенная мьютексом очередь сообщений и c/v, которая сигналится при каждом помещении собщения в очередь.

Напротив, в ОС Windows невозможно сформировать актуальный список процессов, ожидающих на определенном объекте. В процесс может быть доставлена kernel-mode APC, после чего процесс временно покинет состояние ожидания. Второй источник инерционности – это семантика функции WaitForMultipleObjects(bWaitAll=TRUE). Процесс не покинет состояние ожидания до тех пор, пока все объекты не перейдут в signaled state. Концепция этого самого signaled state напрямую диктует, что примитивы синхронизации инерционны. Объект может потерять signaled state если разблокируется ожидающий на нем процесс, просто так потерять signaled state нельзя.

Бесполезно передергивать Auto Reset Event чтобы достичь эффекта бродкаста. Manual Reset Event также бесполезно передергивать. Попытка сделать это вручную – SetEvent(); ResetEvent(); – также не даст результатов. Нет гарантий, что в промежутке между установкой и сбросом события кто-то успеет заметить изменение состояния события и разблокируется.

Это конечно не значит, что conditional variable нельзя сделать в Windows. Очевидно, придется собирать conditional variable из нескольких независимых примитивов синхронизации. Её не получится использовать в WaitForMultipleObjects() совместно с другими объектами синхронизации.

Комментариев нет:

Отправить комментарий

Постоянные читатели

Архив блога