非同期応答の待機中
クライアントがサーバーからの応答の通知を待機している間に実行する処理は、選択した通知メカニズムによって異なります。
クライアントが通知にイベントを使用する場合、通常は WaitForSingleObject 関数または WaitForSingleObjectEx 関数を 呼び出します。 クライアントは、これらの関数のいずれかを呼び出すとブロック状態になります。 これは、クライアントがブロックされている間は CPU 実行サイクルを消費しないため、効率的です。
ポーリングを使用して結果を待機すると、クライアント プログラムは 、関数 RpcAsyncGetCallStatus を繰り返し呼び出すループに入ります。 これは、クライアント プログラムがポーリング ループで他の処理を行う場合に待機する効率的な方法です。 たとえば、後続の非同期リモート プロシージャ 呼び出しのために、小さなチャンクでデータを準備できます。 各チャンクが完了すると、クライアントは未処理の非同期リモート プロシージャ 呼び出しをポーリングして、完了したかどうかを確認できます。
クライアント プログラムは、非同期プロシージャ 呼び出し (APC) を提供できます。これは、非同期リモート プロシージャ 呼び出しの完了時に RPC ランタイム ライブラリが呼び出すコールバック関数の一種です。 クライアント プログラムは、アラート可能な待機状態である必要があります。 これは通常、クライアントが Windows API 関数を呼び出して、それ自体をブロック状態にすることを意味します。 詳細については、「 非同期プロシージャ呼び出し」を参照してください。
Note
非同期呼び出し中に RPC 例外が発生した場合、非同期 RPC ルーチンから完了の通知は返されません。
クライアント プログラムが I/O 完了ポートを使用して完了通知を受信する場合は、 GetQueuedCompletionStatus 関数を呼び出す必要があります。 その場合は、応答を無期限に待機するか、他の処理を続行できます。 応答を待機している間に他の処理を行う場合は、 GetQueuedCompletionStatus 関数を使用して完了ポートをポーリングする必要があります。 この場合、通常は dwMilliseconds を 0 に設定する必要があります。 これにより、非同期呼び出しが完了していない場合でも、 GetQueuedCompletionStatus が直ちに返されます。
クライアント プログラムは、ウィンドウ メッセージ キューを介して完了通知を受け取ることもできます。 この状況では、Windows メッセージと同様に完了メッセージを処理するだけです。
マルチスレッド アプリケーションでは、呼び出しを開始したスレッドが呼び出しから正常に返された後にのみ、クライアントが非同期呼び出しを取り消すことができます。 これにより、同期呼び出しに失敗した後、呼び出しが別のスレッドによって非同期的に取り消されないことが保証されます。 標準的な方法として、同期的に失敗する非同期呼び出しを非同期的に取り消すべきではありません。 異なるスレッドで呼び出しが発行および取り消される可能性がある場合は、クライアント アプリケーションでこの動作を観察する必要があります。 また、呼び出しが取り消された後、クライアント コードは完了通知を待機し、呼び出しを完了する必要があります。 RpcAsyncCancelCall 関数は、完了通知を急ぐだけです。これは、呼び出しを完了するための代わりではありません。
次のコード フラグメントは、クライアント プログラムがイベントを使用して非同期応答を待機する方法を示しています。
// This code fragment assumes that Async is a valid asynchronous
// RPC handle.
if (WaitForSingleObject(Async.u.hEvent, INFINITE) == WAIT_FAILED)
{
RpcRaiseException(APP_ERROR);
}
APC を使用して非同期応答の通知を受け取るクライアント プログラムは、通常、自身をブロック状態にします。 次のコード フラグメントは、これを示しています。
if (SleepEx(INFINITE, TRUE) != WAIT_IO_COMPLETION)
{
RpcRaiseException(APP_ERROR);
}
この場合、RPC ランタイム ライブラリが APC を呼び出すまで、クライアント プログラムはスリープ状態になり、CPU サイクルは消費されません (表示されません)。
次の例では、I/O 完了ポートを使用して非同期応答を待機するクライアントを示します。
// 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);
}
前の例では、 GetQueuedCompletionStatus の呼び出しは、非同期リモート プロシージャ 呼び出しが完了するまで無期限に待機します。
マルチスレッド アプリケーションを記述するときに、1 つの潜在的な落とし穴が発生します。 スレッドがリモート プロシージャ 呼び出しを呼び出し、送信が完了したことを示す通知を受け取る前に終了すると、リモート プロシージャ呼び出しが失敗し、クライアント スタブがサーバーへの接続を閉じる可能性があります。 したがって、リモート プロシージャを呼び出すスレッドは、動作が望ましくない場合に呼び出しが完了または取り消される前に終了しないでください。