Поделиться через


Функции ожидания

Функции ожидания позволяют потоку блокировать собственное выполнение. Функции ожидания не возвращаются до тех пор, пока не будут выполнены указанные условия. Тип функции ожидания определяет набор используемых критериев. При вызове функции ожидания она проверяет, выполнены ли критерии ожидания. Если условия не были выполнены, вызывающий поток переходит в состояние ожидания до тех пор, пока не будут выполнены условия условий ожидания или истекает указанный интервал времени ожидания.

Функции ожидания с одним объектом

Функции SignalObjectAndWait, WaitForSingleObject и WaitForSingleObjectEx требуют дескриптора для одного объекта синхронизации. Эти функции возвращаются при выполнении одного из следующих действий:

  • Указанный объект находится в состоянии сигнала.
  • Истекает интервал времени ожидания. Для интервала ожидания можно задать значение INFINITE , чтобы указать, что время ожидания не будет истекать.

Функция SignalObjectAndWait позволяет вызывающему потоку атомарно задавать состояние объекта как сигнальное и ожидать, пока состояние другого объекта будет задано как сигнальное.

Функции ожидания с несколькими объектами

Функции WaitForMultipleObjects, WaitForMultipleObjectsEx, MsgWaitForMultipleObjects и MsgWaitForMultipleObjectsEx позволяют вызывающму потоку указать массив, содержащий один или несколько дескрипторов объекта синхронизации. Эти функции возвращаются при выполнении одного из следующих действий:

  • Состояние любого из указанных объектов равно signaled или состояние всех объектов — signaled. Вы определяете, будет ли одно или все состояния использоваться в вызове функции.
  • Истекает интервал времени ожидания. Для интервала ожидания можно задать значение INFINITE , чтобы указать, что время ожидания не будет истекать.

Функции MsgWaitForMultipleObjects и MsgWaitForMultipleObjectsEx позволяют указывать объекты входных событий в массиве дескрипторов объектов. Это делается при указании типа входных данных для ожидания во входной очереди потока. Например, поток может использовать MsgWaitForMultipleObjects , чтобы заблокировать его выполнение, пока состояние указанного объекта не будет задано в сигнальное и во входной очереди потока будет доступен ввод с помощью мыши. Поток может использовать функцию GetMessage или PeekMessageA или PeekMessageW для получения входных данных.

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

При ожидании, пока состояние одного объекта будет задано как сигнальное, эти функции с несколькими объектами проверка дескрипторов в массиве в порядке, начиная с индекса 0, до тех пор, пока не будет сигнализован один из объектов. Если несколько объектов становятся сигнальными, функция возвращает индекс первого дескриптора в массиве, объект которого был сигнализован.

Функции ожидания с оповещением

Функции MsgWaitForMultipleObjectsEx, SignalObjectAndWait, WaitForMultipleObjectsEx и WaitForSingleObjectEx отличаются от других функций ожидания тем, что при необходимости они могут выполнять операцию ожидания с оповещением. В операции ожидания с оповещением функция может возвращать при выполнении указанных условий, но она также может возвращать, если система ставит в очередь подпрограмму завершения ввода-вывода или APC для выполнения ожидающего потока. Дополнительные сведения об операциях ожидания с оповещением и процедурах завершения ввода-вывода см. в разделе Синхронизация и перекрытие входных и выходных данных. Дополнительные сведения о APC см. в разделе Асинхронные вызовы процедур.

Зарегистрированные функции ожидания

Функция RegisterWaitForSingleObject отличается от других функций ожидания тем, что операция ожидания выполняется потоком из пула потоков. При выполнении указанных условий функция обратного вызова выполняется рабочим потоком из пула потоков.

По умолчанию зарегистрированная операция ожидания является операцией множественного ожидания. Система сбрасывает таймер каждый раз, когда подается сигнал о событии (или истекает интервал времени ожидания), пока вы не вызовете функцию UnregisterWaitEx для отмены операции. Чтобы указать, что операция ожидания должна выполняться только один раз, задайте параметру dwFlagsобъекта RegisterWaitForSingleObjectзначение WT_EXECUTEONLYONCE.

Если поток вызывает функции, использующие APC, задайте параметру dwFlagsобъекта RegisterWaitForSingleObjectзначение WT_EXECUTEINPERSISTENTTHREAD.

Ожидание адреса

Поток может использовать функцию WaitOnAddress для ожидания изменения значения целевого адреса с какого-либо нежелательного значения на любое другое. Это позволяет потокам ждать изменения значения без необходимости вращаться или обрабатывать проблемы синхронизации, которые могут возникнуть, когда поток захватывает нежелательное значение, но значение меняется, прежде чем поток может ожидать.

WaitOnAddress возвращает, когда код, изменяющий целевое значение, сообщает об изменении, вызывая WakeByAddressSingle для пробуждения одного ожидающего потока или WakeByAddressAll для пробуждения всех ожидающих потоков. Если в параметре WaitOnAddress указан интервал времени ожидания и ни в каких потоках не вызывается функция пробуждения, функция возвращается по истечении интервала ожидания. Если интервал времени ожидания не указан, поток ожидает неограниченное время.

Функции ожидания и интервалы времени ожидания

Точность указанного интервала времени ожидания зависит от разрешения системных часов. Системные часы "тикают" с постоянной скоростью. Если интервал времени ожидания меньше, чем разрешение системных часов, время ожидания может быть меньше указанного периода времени. Если интервал времени ожидания превышает один тик, но меньше двух, то время ожидания может находиться в любом месте от одного до двух тактов и т. д.

Чтобы увеличить точность интервала времени ожидания для функций ожидания, вызовите функцию timeGetDevCaps , чтобы определить поддерживаемую минимальное разрешение таймера, и функцию timeBeginPeriod , чтобы задать разрешение таймера на его минимальное. Будьте осторожны при вызове timeBeginPeriod, так как частые вызовы могут значительно повлиять на системные часы, энергопотребление системы и планировщик. Если вы вызываете timeBeginPeriod, вызовите его один раз в начале приложения и обязательно вызовите функцию timeEndPeriod в самом конце приложения.

Функции ожидания и объекты синхронизации

Функции ожидания могут изменять состояния некоторых типов объектов синхронизации. Изменение происходит только для объекта или объектов, состояние которых привело к возврату функции. Функции ожидания могут изменять состояния объектов синхронизации следующим образом:

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

Функции ожидания и создание окон

При использовании функций ожидания и кода, которые прямо или косвенно создают окна, необходимо соблюдать осторожность. Если поток создает какие-либо окна, он должен обрабатывать сообщения. Широковещательные сообщения отправляются во все окна в системе. Если у вас есть поток, использующий функцию ожидания без интервала ожидания, система будет взаимоблокировкой. Два примера кода, который косвенно создает окна, — это DDE и функция CoInitialize . Поэтому, если у вас есть поток, создающий окна, используйте MsgWaitForMultipleObjects или MsgWaitForMultipleObjectsEx, а не другие функции ожидания.