Attesa della risposta asincrona
Le operazioni eseguite dal client durante l'attesa di ricevere una notifica da parte del server dipendono 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 entra in uno stato bloccato quando chiama una di queste funzioni. Questa operazione è efficiente perché il client non utilizza cicli di esecuzione della CPU mentre è bloccato.
Quando usa il polling per attendere i risultati, il programma client immette 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 piccoli blocchi per una successiva chiamata di procedura remota asincrona. Al termine di ogni blocco, il client può controllare la chiamata di procedura remota asincrona in sospeso per verificare se è completa.
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 asincrona alla procedura remota. Il programma client deve trovarsi in uno stato di attesa allertabile. Questo significa in genere che il client chiama una funzione API di Windows per inserirla in uno stato bloccato. Per ulteriori informazioni, vedere Chiamate di procedura asincrona.
Nota
La notifica di 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 I/O per ricevere notifiche di completamento, deve chiamare la funzione GetQueuedCompletionStatus. Quando lo fa, può attendere per un periodo illimitato per una risposta o continuare a eseguire altre elaborazioni. Se esegue un'altra elaborazione mentre attende una risposta, deve controllare la porta di completamento utilizzando la funzione GetQueuedCompletionStatus. In questo caso, in genere bisogna impostare il dwMilliseconds su zero. Questo causa che GetQueuedCompletionStatus restituisca immediatamente, anche se la chiamata asincrona non sia stata completata.
I programmi client possono ricevere anche notifiche di completamento tramite le code dei messaggi della finestra. In questa situazione, elaborano semplicemente il messaggio di completamento come qualsiasi messaggio di Windows.
In un'applicazione multithreading, una chiamata asincrona può essere annullata dal client solo dopo che il thread che ha originato la chiamata è stato restituito correttamente dalla chiamata. Ciò garantisce che la chiamata non venga annullata in modo asincrono da un altro thread dopo che non è riuscita 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 alla sospensione, senza cicli cpu, fino a quando la libreria di runtime RPC non chiama il servizio APC (non visualizzato).
Nell'esempio seguente viene illustrato un client che usa una porta di completamento 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 indefinitamente fino al completamento della chiamata asincrona della procedura remota.
Una potenziale insidia si verifica quando si scrivono applicazioni multithread. Se un thread richiama una chiamata di procedura remota e quindi termina prima di ricevere la 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.