Реализация функции WaitForMultipleExpressions
Некогорое время назад я разрабатывал одно приложение и столкнулся с весьма не простым случаем синхронизации потоков Функции WaitForMultipleObjects., заставля ющей поток ждать освобождения одного или всех объектов, оказалось недостаточно Мне понадобилась функция, которая позволяла бы задавать более сложные критерии ожидания У меня было три объекта ядра процесс, семафор и событие Мой поток должен был ждать до тех пор, пока не освободтся либо процесс и семафор, либо процесс и событие
Слегка поразмыслив и творчески использовав имеющиеся функции Windows, я создал именно то, что мне требовалось, — функцию WaitWorMulttpleExpressions Ее прототип выглядит так
DWORD WINAPI WaitForMultipleExpressions( DWORD nExpObjectS, CONST HANDLE* phExpObiects, DWORD dwMilliseconds);
Перед ее вызовом Вы должны создать массив описателей (HANDLE) и инициали зировать всс 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 объектов. Могут возвращаться коды и других ошибок |