Успешный вызов WaitForSingleObject или WaitForMultipleObjecls на самом деле меняет состояние некоторых объектов ядра. Под успешным вызовом я имею в виду тот, при котором функция видит, что объект освободился, и возвращает значение, относитель ное WAITOBJECT_0. Вызов считается неудачным, если возвращается WAIT_TIMEOUT или WAIT_FAILED. В последнем случае состояние каких-либо объектов не меняется.
Изменение состояния объекта в результате вызова я называю побочным эффек, том успешного ожидания (successful wait side effect). Например, поток ждет объест «событие с автосбросом" (auto-reset event objcct) (об этих объектах я расскажу чуть позжс) Когда объект переходит в свободное состояние, функция обнаруживает это и может вернуть вызывающему потоку значение WAIT_OBJECT_0. Однако перед самым возвратом из функции событие переводится в занятое состояние — здесь сказывает ся побочный эффект успешного ожидания.
Объекты ядра «событие с автосбросом» ведут себя подобным образом, потому что таково одно из правил, определенных Microsoft для объектов этого типа. Другие объек ты дают иные побочные зффекты, а некоторые — вообще никаких К последним от носятся объекты ядра «процесс" и «поток", так что поток, ожидающий один из этих объектов, никогда не изменит его состояние. Подробнее о том, как ведут себя объек ты ядра, я буду рассказывать при рассмотрении соответствующих объектов.
Чем ценна функция WaitForMultipleObjects, так это тем, что она выполняет все дей ствия на уровне атомарного доступа. Когда поток обращается к этой функции, она ждет освобождения вссх объектов и в случае успеха вызывает в них требуемые по бочные эффекты; причем все действия выполняются как одна операция
Возьмем такой пример. Два потока вызывают WaitForMultipleObjects совершенно одинаково.
HANDLE h[2];
h[0] = hAutoResetEvent1;
// изначально занят
h[1] = hAutoResetEvent2;
// изначально занят
WaitForMulUpleObjects(2, И, TRUE, INFINITE);
На момент вызова WaitForMultipleObjects эти объекты-события заняты, и оба пото ка переходят в режим ожидания Но вот освобождается объект hAutoResetEventl Это становится известным обоим потокам, однако ни один из них не пробуждается, так как объект hAutoResetEvent2 по-прежнему занят. Поскольку потоки все еще ждут, ни какого побочного эффекта для объекта hAutoResetEvent1 не возникает.