Реализация функции WaitForMultipleExpressions
Некогорое время назад я разрабатывал одно приложение и столкнулся с весьма не простым случаем синхронизации потоков. Функции WaitForMultipleObjects, заставляющей поток ждать освобождения одного или всех объектов, оказалось недостаточно. Мне понадобилась функция, которая позволяла бы задавать более сложные критерии ожидания. У меня было три объекта ядра процесс, семафор и событие. Мой поток должен был ждать до тех пор, пока не освободится либо процесс и семафор, либо процесс и событие.
Слегка поразмыслив и творчески использовав имеющиеся функции Windows, я создал именно то, что мне требовалось, — функцию WaitWorMulttpleExpressions. Ее прототип выглядит так:
DWORD WINAPI WaitForMultipleExpressions( DWORD nExpObjectS, CONST HANDLE* phExpObiects, DWORD dwMilliseconds);
Перед ее вызовом Вы должны создать массив описателей (HANDLE) и инициализировать всt cro элементы. Параметр nExpObjects сообщает число элементов в массиве, на который указывает параметр phExpObjects. Этот массив содержит несколько наборов описателей объектов ядра; при этом каждый набор отделяется элементом, равным NULL. Функция WaitForMultipleExpressions считает все объекты в одном наборе объединяемыми логической операцией AND, а сами наборы — объединяемыми логической операцией OR. Поэтому WaitForMultipleExpressions приостанавливает вызы вающий поток до тех пор, пока не освободятся сразу все объекты в одном из наборов.
Вот пример. Допустим, мы работаем с четырьмя объектами ядра (см. таблицу ниже).
Обьект ядра | Значение описателя | ||
Поток | 0x1111 | ||
Семафор | 0x2222 | ||
Событие | 0x3333 | ||
Процесс | 0x4444 |
Инициализировав массив описателей, как показано в следующей таблице, мы со общаем функции WaitForMultipleExpressions приостановить вызывающий поток до тех пор, пока не освободятся поток AND семафор OR семафор AND событие AND про цесс OR поток AND процесс,
Индекс | Значение описателя | Набор | |||
0 | 0x1111 (поток) | 0 | |||
1 | 0x2222 (семафор) | ||||
2 | 0x0000 (OR) | ||||
3 | 0x2222 (семафор) | 1 | |||
4 | 0x3333 (событие) | ||||
5 | 0x4444 (процесс) | ||||
6 | 0x0000 (OR) | ||||
7 | 0x1 1 1 1 (поток) | 2 | |||
8 | 0x4444 (процесс) |
Вы, наверное, помните, что функции WaitForMultipleObjects нельзя передать массив описателей, число элементов в котором превышает 64 (MAXIMUM_WAIT_OBJECTS). Так вот, при использовании WaitForMultipleExpressions массив описателей может быть го раздо больше. Однако у Вас не должно быть более 64 выражений, а в каждом — более 63 описателей. Кроме того, WaitForMulttpleExpresstons будет работать некорректно, если Вы передадите ей хотя бы один описатель мыотекса. (Почему — объясню позже.)
Возвращаемые значения функции WaitForMultipleExpressions показаны в следующей таблице. Если заданное выражение становится истинным, WaitForMultipleExpressions возвращает индекс этого выражения относительно WAIT_OBJECT_0. Если взять тот же пример, то при освобождении объектов "поток" и "процесс" WaitforMultipleExpressions вернет индекс в виде WAIT_OBJECT_0 + 2.
Возвращаемое значение | Описание |
От WAIT_OBJECT_0 до (WAIT_OBJECT_0 + число выражений - 1) | Указывает, какое выражение стало истинным |
WAIT_TIMEOUT | Ни одно выражение не стало истинным в течение заданного времени. |
WAIT_FAILED | Произошла ошибка. Чтобы получить более подробную инфор мацию, вызовите GetLastError. Код ERROR_TOO_MANY_SECRETS означает, что Вы указали более 61 выражений, a ERROR_SEC RET_ТОО_LONG — что по крайней мере в одном выражении указано более 63 объектов. Могут возвращаться коды и других ошибок |