Warten auf die asynchrone Antwort
Was der Client tut, während er wartet, um über eine Antwort vom Server benachrichtigt zu werden, hängt vom ausgewählten Benachrichtigungsmechanismus ab.
Wenn der Client ein Ereignis für Benachrichtigungen verwendet, ruft er in der Regel die WaitForSingleObject-Funktion oder die WaitForSingleObjectEx-Funktion auf. Der Client wechselt in einen blockierten Zustand, wenn er eine dieser Funktionen aufruft. Dies ist effizient, da der Client keine CPU-Ausführungszyklen verbraucht, während er blockiert wird.
Wenn es die Abfrage verwendet, um auf seine Ergebnisse zu warten, tritt das Clientprogramm in eine Schleife ein, die wiederholt die Funktion RpcAsyncGetCallStatus aufruft. Dies ist eine effiziente Methode zum Warten, wenn Ihr Clientprogramm eine andere Verarbeitung in der Abfrageschleife ausführt. Für instance kann es Daten in kleinen Blöcken für einen nachfolgenden asynchronen Remoteprozeduraufruf vorbereiten. Nachdem die einzelnen Blöcke abgeschlossen sind, kann Ihr Client den ausstehenden asynchronen Remoteprozeduraufruf abfragen, um zu überprüfen, ob er abgeschlossen ist.
Ihr Clientprogramm kann einen asynchronen Prozeduraufruf (Asynchrone Prozeduraufrufe, APC) bereitstellen. Hierbei handelt es sich um eine Art Rückruffunktion, die von der RPC-Laufzeitbibliothek aufgerufen wird, wenn der asynchrone Remoteprozeduraufruf abgeschlossen ist. Ihr Clientprogramm muss sich in einem warnbaren Wartezustand befinden. Dies bedeutet in der Regel, dass der Client eine Windows-API-Funktion aufruft, um sich in einen blockierten Zustand zu versetzen. Weitere Informationen finden Sie unter Asynchrone Prozeduraufrufe.
Hinweis
Eine Abschlussbenachrichtigung wird von einer asynchronen RPC-Routine nicht zurückgegeben, wenn während eines asynchronen Aufrufs eine RPC-Ausnahme ausgelöst wird.
Wenn Ihr Clientprogramm einen E/A-Vervollständigungsport zum Empfangen von Vervollständigungsbenachrichtigungen verwendet, muss es die GetQueuedCompletionStatus-Funktion aufrufen. Wenn dies der Fall ist, kann sie entweder unbegrenzt auf eine Antwort warten oder eine andere Verarbeitung durchführen. Wenn eine andere Verarbeitung ausgeführt wird, während auf eine Antwort gewartet wird, muss der Vervollständigungsport mit der GetQueuedCompletionStatus-Funktion abgefragt werden . In diesem Fall müssen die dwMillisekunden in der Regel auf 0 festgelegt werden. Dadurch wird GetQueuedCompletionStatus sofort zurückgegeben, auch wenn der asynchrone Aufruf nicht abgeschlossen wurde.
Clientprogramme können auch Vervollständigungsbenachrichtigungen über ihre Fensternachrichtenwarteschlangen empfangen. In dieser Situation verarbeiten sie einfach die Vervollständigungsnachricht wie jede Windows-Nachricht.
In einer Multithreadanwendung kann ein asynchroner Aufruf vom Client erst abgebrochen werden, nachdem der Thread, aus dem der Aufruf stammt, erfolgreich vom Aufruf zurückgegeben wurde. Dadurch wird sichergestellt, dass der Aufruf nicht asynchron von einem anderen Thread abgebrochen wird, nachdem ein synchroner Aufruf fehlgeschlagen ist. Standardmäßig sollte ein asynchroner Aufruf, der synchron fehlschlägt, nicht asynchron abgebrochen werden. Die Clientanwendung muss dieses Verhalten beachten, wenn Aufrufe für verschiedene Threads ausgegeben und abgebrochen werden können. Außerdem muss der Clientcode nach dem Abbrechen des Aufrufs auf die Vervollständigungsbenachrichtigung warten und den Aufruf abschließen. Die RpcAsyncCancelCall-Funktion übereilt einfach die Vervollständigungsbenachrichtigung. es ist kein Ersatz für das Abschließen des Anrufs.
Das folgende Codefragment veranschaulicht, wie ein Clientprogramm ein Ereignis verwenden kann, um auf eine asynchrone Antwort zu warten.
// This code fragment assumes that Async is a valid asynchronous
// RPC handle.
if (WaitForSingleObject(Async.u.hEvent, INFINITE) == WAIT_FAILED)
{
RpcRaiseException(APP_ERROR);
}
Clientprogramme, die eine APC verwenden, um Benachrichtigungen über eine asynchrone Antwort zu erhalten, versetzen sich in der Regel in einen blockierten Zustand. Das folgende Codefragment zeigt dies.
if (SleepEx(INFINITE, TRUE) != WAIT_IO_COMPLETION)
{
RpcRaiseException(APP_ERROR);
}
In diesem Fall wechselt das Clientprogramm in den Ruhemodus und verbraucht keine CPU-Zyklen, bis die RPC-Laufzeitbibliothek den APC aufruft (nicht angezeigt).
Das nächste Beispiel zeigt einen Client, der einen E/A-Vervollständigungsport verwendet, um auf eine asynchrone Antwort zu warten.
// 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);
}
Im vorherigen Beispiel wartet der Aufruf von GetQueuedCompletionStatus unbegrenzt, bis der Aufruf der asynchronen Remoteprozedur abgeschlossen ist.
Ein potenzieller Fallstrick tritt beim Schreiben von Multithreadanwendungen auf. Wenn ein Thread einen Remoteprozeduraufruf aufruft und dann beendet wird, bevor er die Benachrichtigung erhält, dass der Sendevorgang abgeschlossen ist, schlägt der Remoteprozeduraufruf möglicherweise fehl, und der Client-Stub schließt möglicherweise die Verbindung mit dem Server. Daher sollten Threads, die eine Remoteprozedur aufrufen, nicht beendet werden, bevor der Aufruf abgeschlossen oder abgebrochen wird, wenn das Verhalten unerwünscht ist.