Partilhar via


Chamadas de procedimento assíncronas

Uma de chamada de procedimento assíncrono (APC) é uma função que é executada de forma assíncrona no contexto de um thread específico. Quando um APC é enfileirado para um thread, o sistema emite uma interrupção de software. Na próxima vez que o thread for agendado, ele executará a função APC. Um APC gerado pelo sistema é chamado de APC de modo kernel. Um APC gerado por um aplicativo é chamado de modo de usuário APC. Um thread deve estar em um estado alertável para executar um APC de modo de usuário.

Cada thread tem sua própria fila APC. Um aplicativo enfileira um APC para um thread chamando a funçãoQueueUserAPC. O thread de chamada especifica o endereço de uma função APC na chamada para QueueUserAPC. O enfileiramento de um APC é uma solicitação para que o thread chame a função APC.

Quando um APC de modo de usuário é enfileirado, o thread para o qual ele está enfileirado não é direcionado para chamar a função APC, a menos que esteja em um estado alertável. Um thread entra em um estado alertável quando chama o SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsExou função WaitForSingleObjectEx. Se a espera for satisfeita antes que o APC seja enfileirado, o thread não estará mais em um estado de espera alertável, portanto, a função APC não será executada. No entanto, o APC ainda está na fila, portanto, a função APC será executada quando o thread chamar outra função de espera alertável.

As funções ReadFileEx, SetWaitableTimer, SetWaitableTimerExe WriteFileEx são implementadas usando um APC como mecanismo de retorno de chamada de notificação de conclusão.

Se você estiver usando um pool de threads , observe que os APCs não funcionam tão bem quanto outros mecanismos de sinalização porque o sistema controla o tempo de vida dos threads do pool de threads, portanto, é possível que um thread seja encerrado antes que a notificação seja entregue. Em vez de usar um mecanismo de sinalização baseado em APC, como o parâmetro pfnCompletionRoutine de SetWaitableTimer ou SetWaitableTimerEx, use um objeto de espera, como um temporizador criado com CreateThreadpoolTimer. Para E/S, use um objeto de conclusão de E/S criado com CreateThreadpoolIo ou uma estrutura deOVERLAPPED baseada em hEventonde o evento pode ser passado para a função deSetThreadpoolWait.

Sincronização interna

Quando uma solicitação de E/S é emitida, uma estrutura é alocada para representar a solicitação. Essa estrutura é chamada de pacote de solicitação de E/S (IRP). Com E/S síncrona, o thread constrói o IRP, envia-o para a pilha de dispositivos e aguarda no kernel a conclusão do IRP. Com E/S assíncrona, o thread cria o IRP e o envia para a pilha de dispositivos. A pilha pode concluir o IRP imediatamente ou pode retornar um status pendente indicando que a solicitação está em andamento. Quando isso acontece, o IRP ainda está associado ao thread, portanto, ele será cancelado se o thread terminar ou chamar uma função como CancelIo. Enquanto isso, o thread pode continuar a executar outras tarefas enquanto a pilha de dispositivos continua a processar o IRP.

Há várias maneiras pelas quais o sistema pode indicar que o IRP foi concluído:

  • Atualize a estrutura sobreposta com o resultado da operação para que o thread possa sondar para determinar se a operação foi concluída.
  • Sinalize o evento na estrutura sobreposta para que um thread possa sincronizar no evento e ser acordado quando a operação for concluída.
  • Enfileire o IRP para o APC pendente do thread para que o thread execute a rotina do APC quando entrar em um estado de espera alertável e retornar da operação de espera com um status indicando que ele executou uma ou mais rotinas APC.
  • Enfileire o IRP para uma porta de conclusão de E/S, onde será executado pelo próximo thread que aguarda na porta de conclusão.

Os threads que aguardam em uma porta de conclusão de E/S não aguardam em um estado alertável. Portanto, se esses threads emitirem IRPs definidos para serem concluídos como APCs para o thread, essas finalizações de IPC não ocorrerão em tempo hábil; eles ocorrerão somente se o thread pegar uma solicitação da porta de conclusão de E/S e, em seguida, entrar em uma espera alertável.

Usando um temporizador de espera com um de chamada de procedimento assíncrono