비동기 프로시저 호출

APC( 비동기 프로시저 호출 )는 특정 스레드의 컨텍스트에서 비동기적으로 실행되는 함수입니다. APC가 스레드에 큐에 대기하는 경우 시스템에서 소프트웨어 인터럽트를 실행합니다. 다음에 스레드가 예약되면 APC 함수가 실행됩니다. 시스템에서 생성된 APC를 커널 모드 APC라고 합니다. 애플리케이션에서 생성된 APC를 사용자 모드 APC라고 합니다. 사용자 모드 APC를 실행하려면 스레드가 경고 가능한 상태여야 합니다.

각 스레드에는 자체 APC 큐가 있습니다. 애플리케이션은 QueueUserAPC 함수를 호출하여 APC를 스레드로 큐에 대기합니다. 호출 스레드는 QueueUserAPC 호출에서 APC 함수의 주소를 지정합니다. APC의 큐는 스레드가 APC 함수를 호출하도록 요청하는 것입니다.

사용자 모드 APC가 큐에 대기 중인 경우 경고 가능한 상태가 아닌 한 APC 함수를 호출하도록 지시되지 않습니다. 스레드는 SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx 또는 WaitForSingleObjectEx 함수를 호출할 때 경고 가능한 상태로 전환됩니다. APC가 큐에 대기되기 전에 대기가 충족되면 스레드가 더 이상 경고 가능한 대기 상태가 아니므로 APC 함수가 실행되지 않습니다. 그러나 APC는 여전히 큐에 대기되므로 스레드가 경고 가능한 다른 대기 함수를 호출할 때 APC 함수가 실행됩니다.

ReadFileEx, SetWaitableTimer, SetWaitableTimerExWriteFileEx 함수는 완료 알림 콜백 메커니즘으로 APC를 사용하여 구현됩니다.

스레드 풀을 사용하는 경우 시스템이 스레드 풀 스레드의 수명을 제어하므로 알림이 전달되기 전에 스레드가 종료될 수 있으므로 APC는 다른 신호 메커니즘뿐만 아니라 작동하지 않습니다. SetWaitableTimer 또는 SetWaitableTimerExpfnCompletionRoutine 매개 변수와 같은 APC 기반 신호 메커니즘을 사용하는 대신 CreateThreadpoolTimer로 만든 타이머와 같은 대기 가능한 개체를 사용합니다. I/O의 경우 CreateThreadpoolIo로 만든 I/O 완성 개체 또는 이벤트를 SetThreadpoolWait 함수에 전달할 수 있는 hEvent 기반 OVERLAPPED 구조를 사용합니다.

동기화 내부

I/O 요청이 실행되면 요청을 나타내는 구조체가 할당됩니다. 이 구조를 IRP(I/O 요청 패킷)라고 합니다. 동기 I/O를 사용하면 스레드는 IRP를 빌드하고, 디바이스 스택으로 보내고, IRP가 완료될 때까지 커널에서 기다립니다. 비동기 I/O를 사용하면 스레드가 IRP를 빌드하고 디바이스 스택으로 보냅니다. 스택은 IRP를 즉시 완료하거나 요청이 진행 중임을 나타내는 보류 중인 상태 반환할 수 있습니다. 이 경우 IRP는 여전히 스레드와 연결되므로 스레드가 종료되거나 CancelIo와 같은 함수를 호출하면 취소됩니다. 그 동안 스레드는 디바이스 스택이 IRP를 계속 처리하는 동안 다른 작업을 계속 수행할 수 있습니다.

시스템에서 IRP가 완료되었음을 나타낼 수 있는 몇 가지 방법이 있습니다.

  • 스레드가 폴링하여 작업이 완료되었는지 여부를 확인할 수 있도록 겹치는 구조를 작업 결과로 업데이트합니다.
  • 스레드가 이벤트에서 동기화되고 작업이 완료될 때 절전 모드를 깨울 수 있도록 겹치는 구조의 이벤트에 신호를 보냅니다.
  • 스레드가 경고 대기 상태가 될 때 APC 루틴을 실행하고 하나 이상의 APC 루틴을 실행했음을 나타내는 상태 사용하여 대기 작업에서 반환되도록 스레드의 보류 중인 APC에 IRP를 큐에 넣습니다.
  • IRP를 I/O 완료 포트로 큐에 대기합니다. 이 포트는 완료 포트에서 대기하는 다음 스레드에서 실행됩니다.

I/O 완료 포트에서 대기하는 스레드는 경고 가능 상태에서 기다리지 않습니다. 따라서 이러한 스레드가 스레드에 APC로 완료되도록 설정된 IRP를 발급하는 경우 해당 IPC 완료는 적시에 발생하지 않습니다. 스레드가 I/O 완료 포트에서 요청을 선택한 다음 경고 대기를 입력하는 경우에만 발생합니다.

비동기 프로시저 호출과 함께 대기 가능한 타이머 사용