Синхронизация потоков в операционной системе Windows, страница 10

Функция WaitForMultipleObjects возвращает управление вызвавшему потоку в случае, если хотя бы один из ожидаемых объектов изменил свое состояние. Что| делать, если вы хотите, чтобы управление было возвращено только в случае, если абсолютно все объекты изменили свое состояние? Для этого необходимо присвоить аргументу bWaitAll этой функции значение TRUE.

Еще одним вызовом, позволяющим ожидать изменения состояния нескольких объектов, является вызов MsgWaitForMultipleObjectsEx. Этот вызов позволяет ждать не только изменения состояния объектов, но также передачи программе каких-либо системных сообщений. В частности, программа может ожидать изменения состояния объекта и в то же время реагировать на системные сообщения, такие как, например, WM_PAINT.

Вызов MsgWaitForMultipleObjectsEx можно использовать также для ожидания одновременно и объектов, и сообщений. Другими словами, функция вернет управление потоку только в случае, если все указанные объекты перейдут в сигнальное состояние и при этом будут приняты все указанные сообщения. Конечно, в этой ситуации вы не сможете обрабатывать системные сообщения до тех пор, пока все интересующие объекты не перейдут в сигнальное состояние. Это обстоятельство существенно снижает полезность подобного вызова.

При переходе в сигнальное состояние одного из ожидаемых объектов вызов WaitForMultipleObjects возвращает значение из заданного диапазона, указывающее на то, какой именно объект изменил состояние. Если поток ожидал изменения состояния  нескольких объектов,  значение, возвращенное функцией MaitForMultipleObjects, непредсказуемо, однако оно все равно принадлежит заданному диапазону. Диапазон включает в себя числа от WAIT_OBJECT_0 до WAIT_OBJECT_0 плюс количество элементов в массиве дескрипторов объектов синхронизации. Значение WAIT ABANDON_0 (совпадает с WAIT_ABANDON) является нижней границей диапазона возвращаемых значений для мьютекса, использование которого было прервано. И наконец, значение WAIT_TIMEOUT обозначает, что истекло время, в течение которого функция WaitForMultipleObjects должна была ожидать изменения состояния объектов.

Ожидание объектов в настороженном состоянии

Для ожидания изменения состояния объектов можно использовать три других вызова: WaitForSingleObjectEx, MsgWaitForMultipleObjectsEx и WaitForMultipleObjectsEx. В отличие аналогов, в именах которых отсутствует суффикс Ех, эти вызовы позволяют ожидать изменения состояния объектов в так называемом «настороженном» (alertable) состоянии.

Что такое настороженное состояние? Если поток находится в состоянии настороженного ожидания, он может выполнять асинхронные вызовы процедур (Asynchronous Procedure Call, APC). Чаще всего функции АРС используются для организации асинхронного ввода/вывода. Ваш поток может приказать выполнить функцию АРС в другом, уже существующем и работающем потоке, асинхронно для этого потока. Для этого ваш поток может использовать вызов QueueUserAPC. Однако для этого другой поток должен находиться в «настороженном» состоянии. Если другой поток не находится в «настороженном» состоянии, функция АРС ставится в очередь на исполнение в указанном потоке. Исполнение всех функций, стоящих в очереди для некоторого потока, происходит в момент, когда поток переходит в «настороженное» состояние. Перевести поток в «настороженное» состояние можно либо при помощи упомянутых выше трех вызовов (WaitForSingleObjectEx, MsgWaitForMultipleObjectsEx и WaitForMultipleObjectsEx), либо при помощи вызова SleepEx.

Таймер синхронизации

Еще одним способом вызова функции АРС является таймер синхронизации (waitable timer). Для создания нового или открытия уже существующего таймера синхронизации можно использовать функции CreateWaitableTimer и OpenWaitableTimer, которые работают в точности так же, как работают аналогичные функции, предназначенные для создания и открытия других объектов синхронизации. Таймер переходит в сигнальное состояние в момент, когда истекает соответствующий ему временной интервал. Таймер синхронизации можно настроить таким образом, что в момент истечения его периода времени происходит вызов функции АРС в некотором потоке. Как и в других подобных случаях, вызов АРС не сработает до тех пор, пока целевой поток не перейдет в настороженное состояние.