Enviando a resposta assíncrona
Quando a chamada assíncrona é concluída, o servidor envia uma resposta ao cliente chamando a função RpcAsyncCompleteCall e passando-a pelo identificador assíncrono. Essa chamada é necessária mesmo se a chamada assíncrona tiver um valor retornado nulo e nenhum parâmetro [out]. Se a função tiver um valor retornado, ela será passada por referência a RpcAsyncCompleteCall.
Quando o servidor chama RpcAsyncCompleteCall ou RpcAsyncAbortCall ou uma chamada é concluída porque uma exceção foi gerada na rotina do gerenciador de servidores, a biblioteca de tempo de execução do RPC destrói automaticamente o identificador assíncrono do servidor.
Observação
O servidor deve concluir a atualização dos parâmetros [in, out] e [out] antes de chamar RpcAsyncCompleteCall. Nenhuma alteração pode ser feita nesses parâmetros ou no identificador assíncrono depois de chamar RpcAsyncCompleteCall. Se a chamada da função RpcAsyncCompleteCall falhar, o runtime do RPC liberará os parâmetros.
O exemplo a seguir demonstra uma simples chamada de procedimento assíncrono.
#define DEFAULT_ASYNC_DELAY 20;
#define ASYNC_CANCEL_CHECK 100;
void AsyncFunc(IN PRPC_ASYNC_STATE pAsync,
IN RPC_BINDING_HANDLE hBinding,
IN OUT unsigned long nAsychDelay)
{
int nReply = 1;
RPC_STATUS status;
unsigned long nTmpAsychDelay;
int i;
if (nAsychDelay < 0){
nAsychDelay = DEFAULT_ASYNC_DELAY;
}else if (nAsychDelay < 100){
nAsychDelay = 100;
}
// We only call RpcServerTestCancel if the call
// takes longer than ASYNC_CANCEL_CHECK ms
if(nAsychDelay > ASYNC_CANCEL_CHECK){
nTmpAsychDelay = nAsychDelay/100;
for (i = 0; i < 100; i++){
Sleep(nTmpAsychDelay);
if (i%5 == 0){
fprintf(stderr,
"\rRunning AsyncFunc (%lu ms) (%d%c) ... ",
nAsychDelay, i+5, PERCENT);
status =
RpcServerTestCancel(
RpcAsyncGetCallHandle(pAsync));
if (status == RPC_S_OK){
fprintf(stderr,
"\nAsyncFunc has been canceled!!!\n");
break;
}else if (status != RPC_S_CALL_IN_PROGRESS){
printf(
"RpcAsyncInitializeHandle returned 0x%x\n",
status);
exit(status);
}
}
}
}else{
Sleep(nAsychDelay);
}
printf("\nCalling RpcAsyncCompleteCall\n");
status = RpcAsyncCompleteCall(pAsync, &nReply);
printf("RpcAsyncCompleteCall returned 0x%x\n", status);
if (status){
exit(status);
}
}
Para simplificar, essa rotina de servidor assíncrona não processa dados reais. Ele simplesmente se coloca para dormir por um tempo.
Observação
A função RpcAsyncCompleteCall pode ser chamada no thread que recebeu a chamada ou em qualquer outro thread no processo. Se todos os dados necessários para concluir a chamada estiverem prontamente disponíveis, o servidor poderá preenchê-los no mesmo thread e chamar rpcAsyncCompleteCall no mesmo thread. Essa abordagem salva algumas mudanças de contexto e melhora o desempenho. Tais chamadas são chamadas oportunistamente assíncronas.
Tópicos relacionados