等候非同步回復
用戶端在等候收到來自伺服器的回復通知時所執行的動作取決於它選取的通知機制。
如果用戶端使用事件來通知,它通常會呼叫 WaitForSingleObject 函式或 WaitForSingleObjectEx 函 式。 用戶端在呼叫其中一個函式時進入封鎖狀態。 這是有效率的,因為用戶端在封鎖時不會耗用 CPU 執行循環。
當用戶端程式使用輪詢來等候其結果時,會輸入重複呼叫 RpcAsyncGetCallStatus函式的迴圈。 如果您的用戶端程式在輪詢迴圈中執行其他處理,這是等候的有效方法。 例如,它可以針對後續的非同步遠端程序呼叫,以小型區塊準備資料。 完成每個區塊之後,您的用戶端可以輪詢未處理的非同步遠端程序呼叫,以查看其是否完成。
您的用戶端程式可以提供非同步程序呼叫 (APC) ,這是 RPC 執行時間程式庫會在非同步遠端程序呼叫完成時叫用的回呼函式類型。 您的用戶端程式必須處於可警示的等候狀態。 這通常表示用戶端會呼叫 Windows API 函式,讓其本身處於封鎖狀態。 如需詳細資訊,請參閱 非同步程序呼叫。
注意
如果在非同步呼叫期間引發 RPC 例外狀況,則不會從非同步 RPC 常式傳回完成通知。
如果您的用戶端程式使用 I/O 完成埠來接收完成通知,它必須呼叫 GetQueuedCompletionStatus 函式。 這麼做時,它可以無限期等候回應,或繼續執行其他處理。 如果在等候回復時執行其他處理,則必須使用 GetQueuedCompletionStatus 函式輪詢完成埠。 在此情況下,通常需要將 dwMilliseconds 設定為零。 這會導致 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);
}
在此情況下,用戶端程式會進入睡眠狀態,不耗用 CPU 週期,直到 RPC 執行時間程式庫呼叫 APC (未顯示) 為止。
下一個範例示範使用 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 的呼叫會無限期等候,直到非同步遠端程序呼叫完成為止。
撰寫多執行緒應用程式時,會發生一個潛在的陷阱。 如果執行緒叫用遠端程序呼叫,然後在收到傳送完成的通知之前終止,遠端程序呼叫可能會失敗,而且用戶端存根可能會關閉與伺服器的連線。 因此,呼叫遠端程式的執行緒不應該在呼叫完成或取消行為時終止。