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


Асинхронные вызовы процедур

Асинхронный вызов процедуры (APC) — это функция, которая выполняется асинхронно в контексте определенного потока. Когда APC помещается в очередь в поток, система выдает прерывание программного обеспечения. При следующем планировании потока будет запущена функция APC. APC, созданный системой, называется APC в режиме ядра. APC, созданный приложением, называется APC в пользовательском режиме. Чтобы запустить APC в пользовательском режиме, поток должен находиться в состоянии предупреждения.

Каждый поток имеет собственную очередь APC. Приложение помещает APC в очередь в поток, вызывая функцию QueueUserAPC . Вызывающий поток указывает адрес функции APC в вызове QueueUserAPC. Очередь APC — это запрос потока на вызов функции APC.

Когда APC в пользовательском режиме помещается в очередь, поток, к которому он находится в очереди, не направляется на вызов функции APC, если только он не находится в состоянии предупреждения. Поток переходит в состояние оповещения при вызове функции SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx или WaitForSingleObjectEx . Если ожидание выполнено до постановки APC в очередь, поток больше не находится в состоянии ожидания с возможностью предупреждения, поэтому функция APC не будет выполняться. Однако APC по-прежнему находится в очереди, поэтому функция APC будет выполняться, когда поток вызывает другую функцию ожидания с оповещением.

Функции ReadFileEx, SetWaitableTimer, SetWaitableTimerEx и WriteFileEx реализуются с помощью APC в качестве механизма обратного вызова уведомления о завершении.

Если вы используете пул потоков, обратите внимание, что APC не работают так же, как другие механизмы сигнализации, так как система управляет временем существования потоков пула потоков, поэтому поток может быть завершен до доставки уведомления. Вместо использования механизма сигнализации на основе APC, например параметра pfnCompletionRoutinesetWaitableTimer или SetWaitableTimerEx, используйте объект для ожидания, например таймер, созданный с помощью CreateThreadpoolTimer. Для операций ввода-вывода используйте объект завершения ввода-вывода, созданный с помощью CreateThreadpoolIo, или структуру OVERLAPPED на основе hEvent, в которой событие можно передать в функцию SetThreadpoolWait.

Внутренние службы синхронизации

При выдаче запроса ввода-вывода выделяется структура для представления запроса. Эта структура называется пакетом запроса ввода-вывода (IRP). При синхронном вводе-выводе поток создает IRP, отправляет его в стек устройств и ожидает завершения его в ядре. При использовании асинхронного ввода-вывода поток создает IRP и отправляет его в стек устройств. Стек может завершить IRP немедленно или вернуть состояние ожидания, указывающее, что запрос выполняется. В этом случае IRP по-прежнему связан с потоком, поэтому он будет отменен, если поток завершается или вызывает функцию , например CancelIo. В то же время поток может продолжать выполнять другие задачи, пока стек устройств продолжает обрабатывать IRP.

Существует несколько способов, которыми система может указать, что IRP завершен.

  • Обновите перекрываемую структуру с помощью результата операции, чтобы поток смог опросить, завершена ли операция.
  • Сообщите о событии в перекрывающейся структуре, чтобы поток смог синхронизироваться с событием и разбудиться после завершения операции.
  • В очереди IRP в ожидающий APC потока, чтобы поток выполнял подпрограмму APC, когда он переходит в состояние ожидания с оповещением, и возвращался из операции ожидания с состоянием, указывающим, что он выполнил одну или несколько подпрограмм APC.
  • Поставить IRP в очередь на порт завершения ввода-вывода, где он будет выполняться следующим потоком, ожидающим порта завершения.

Потоки, ожидающие завершения ввода-вывода через порт ввода-вывода, не ожидаются в состоянии предупреждения. Таким образом, если эти потоки выдают irP, которые настроены для завершения в качестве APC для потока, эти завершения IPC не будут выполняться своевременно; Они будут возникать только в том случае, если поток получает запрос от порта завершения ввода-вывода, а затем вводит оповещенное ожидание.

Использование таймера ожидания с асинхронным вызовом процедуры