Материал взят из 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() совместно с другими объектами синхронизации.
Подписаться на:
Комментарии к сообщению (Atom)
Постоянные читатели
Архив блога
-
▼
2010
(55)
-
▼
апреля
(28)
- Стив Джобс рассказал, почему Apple "не пускает" Fl...
- Работа с локальным SVN-репозитарием
- Как в Mac OS снять блокировку/защиту из всех файло...
- Как получить пути к наиболее часто используемым па...
- Как автоматически копировать нужные заголовки в ну...
- Чем заменить функцию stricmp в iPhone-проекте
- Легендарный редактор vi
- Как выяснить причину EXC_BAD_ACCESS в Xcode
- Что делать, если в Xcode-отладчике невозможно пере...
- Как изменить размер стека потока средствами pthrea...
- Интересные материалы для C++ программистов в блоге...
- Принципы Agile Software Development
- Знакомство с компилятором GCC
- Антипаттерны
- man xcodebuild (справка по команде)
- Как сделать скрипт для компиляции и линковки сразу...
- Какой аналог у SetEvent (Win32) в pthread?
- Pthread Condition Variables и Windows Events (Креа...
- Шпаргалка по TinyXML
- Мои любимые книги по программированию
- Из блога Сергея Меднова: Знает ли Apple, для чего ...
- Вопросы на проверку знания языка C++
- Использование pthread (POSIX) функций для многопот...
- Xcode — странные выходки отладчика
- Проблемы со статическими библиотеками при разработ...
- Переименование Xcode-проекта и приложения (для iPh...
- Как совмещать C++ и Objective C код в одном файле ...
- Как удалить badge-кружочки из TabBar вкладок
-
▼
апреля
(28)
Комментариев нет:
Отправить комментарий