Attesa della risposta asincrona
Ciò che il client esegue durante l'attesa di ricevere una notifica di una risposta dal server dipende dal meccanismo di notifica selezionato.
Se il client usa un evento per la notifica, in genere chiamerà la funzione WaitForSingleObject o la funzione WaitForSingleObjectEx. Il client immette uno stato bloccato quando chiama una di queste funzioni. Questo è efficiente perché il client non usa cicli di esecuzione della CPU mentre è bloccato.
Quando usa il polling per attendere i risultati, il programma client entra in un ciclo che chiama ripetutamente la funzione RpcAsyncGetCallStatus. Si tratta di un metodo efficiente di attesa se il programma client esegue altre elaborazioni nel ciclo di polling. Ad esempio, può preparare i dati in blocchi di piccole dimensioni per una successiva chiamata di procedura remota asincrona. Al termine di ogni blocco, il client può eseguire il polling della chiamata di procedura remota asincrona in sospeso per verificare se è stato completato.
Il programma client può fornire una chiamata di procedura asincrona (APC), ovvero un tipo di funzione di callback che la libreria di runtime RPC richiamerà al termine della chiamata alla procedura remota asincrona. Il programma client deve essere in uno stato di attesa avvisabile. Questo significa in genere che il client chiama una funzione API di Windows per inserirla in uno stato bloccato. Per altre informazioni, vedere Chiamate di procedura asincrone.
Nota
La notifica del completamento non verrà restituita da una routine RPC asincrona se viene generata un'eccezione RPC durante una chiamata asincrona.
Se il programma client usa una porta di completamento di I/O per ricevere la notifica di completamento, deve chiamare la funzione GetQueuedCompletionStatus . In caso contrario, può attendere in modo indefinito una risposta o continuare a eseguire altre operazioni di elaborazione. Se esegue altre operazioni di elaborazione mentre attende una risposta, deve eseguire il polling della porta di completamento con la funzione GetQueuedCompletionStatus . In questo caso, in genere deve impostare i dwMilliseconds su zero. In questo modo GetQueuedCompletionStatus restituisce immediatamente, anche se la chiamata asincrona non è stata completata.
I programmi client possono anche ricevere notifiche di completamento tramite le code dei messaggi della finestra. In questa situazione, semplicemente elaborano il messaggio di completamento perché sarebbero tutti i messaggi di Windows.
In un'applicazione multithreaded, una chiamata asincrona può essere annullata dal client solo dopo che il thread che ha generato la chiamata ha restituito correttamente dalla chiamata. Ciò garantisce che la chiamata non venga annullata in modo asincrono da un altro thread dopo aver superato una chiamata sincrona. Come procedura standard, una chiamata asincrona che non riesce in modo sincrono non deve essere annullata in modo asincrono. L'applicazione client deve osservare questo comportamento se le chiamate possono essere rilasciate e annullate in thread diversi. Inoltre, dopo l'annullamento della chiamata, il codice client deve attendere la notifica di completamento e completare la chiamata. La funzione RpcAsyncCancelCall esegue semplicemente la notifica di completamento; non è un sostituto per completare la chiamata.
Il frammento di codice seguente illustra come un programma client può usare un evento per attendere una risposta asincrona.
// This code fragment assumes that Async is a valid asynchronous
// RPC handle.
if (WaitForSingleObject(Async.u.hEvent, INFINITE) == WAIT_FAILED)
{
RpcRaiseException(APP_ERROR);
}
I programmi client che usano un APC per ricevere una notifica di una risposta asincrona vengono in genere inseriti in uno stato bloccato. Il frammento di codice seguente mostra questo.
if (SleepEx(INFINITE, TRUE) != WAIT_IO_COMPLETION)
{
RpcRaiseException(APP_ERROR);
}
In questo caso, il programma client passa a sospensione, senza cicli di CPU, fino a quando la libreria di runtime RPC chiama il servizio APC (non visualizzato).
Nell'esempio successivo viene illustrato un client che usa una porta di completamento di I/O per attendere una risposta asincrona.
// This code fragment assumes that Async is a valid asynchronous
// RPC handle.
if (!GetQueuedCompletionStatus(
Async.u.IOC.hIOPort,
&Async.u.IOC.dwNumberOfBytesTransferred,
&Async.u.IOC.dwCompletionKey,
&Async.u.IOC.lpOverlapped,
INFINITE))
{
RpcRaiseException(APP_ERROR);
}
Nell'esempio precedente, la chiamata a GetQueuedCompletionStatus attende in modo indefinito fino al completamento della chiamata alla procedura remota asincrona.
Un potenziale errore si verifica durante la scrittura di applicazioni multithreading. Se un thread richiama una chiamata di routine remota e termina prima di ricevere una notifica che l'invio è stato completato, la chiamata di procedura remota potrebbe non riuscire e lo stub del client potrebbe chiudere la connessione al server. Pertanto, i thread che chiamano una routine remota non devono terminare prima che la chiamata venga completata o annullata quando il comportamento è indesiderato.