WaitForSingleObject、WaitForMulitpleObjects和SignalObjectAndWait執行緒同步

ForTechnology發表於2011-08-07
WaitForSingleObject、WaitForMulitpleObjects和SignalObjectAndWait執行緒同步

2010-12-10 15:47 型別:生活點滴

  使用者模式的執行緒同步機制效率高,如果需要考慮執行緒同步問題,應該首先考慮使用者模式的執行緒同步方法。但是,使用者模式的執行緒同步有限制,對於多個程式之間的執行緒同步,使用者模式的執行緒同步方法無能為力。這時,只能考慮使用核心模式。

  Windows提供了許多核心物件來實現執行緒的同步。對於執行緒同步而言,這些核心物件有兩個非常重要的狀態:“已通知”狀態,“未通知”狀態(也有翻譯為:受信狀態,未受信狀態)。Windows提供了幾種核心物件可以處於已通知狀態和未通知狀態:程式、執行緒、作業、檔案、控制檯輸入/輸出/錯誤流、事件、等待定時器、訊號量、互斥物件。

  你可以通知一個核心物件,使之處於“已通知狀態”,然後讓其他等待在該核心物件上的執行緒繼續執行。你可以使用Windows提供的API函式,等待函式來等待某一個或某些核心物件變為已通知狀態。

  你可以使用WaitForSingleObject函式來等待一個核心物件變為已通知狀態:

DWORD WaitForSingleObject(
  HANDLE hObject, //指明一個核心物件的控制程式碼
  DWORD dwMilliseconds); //等待時間
  該函式需要傳遞一個核心物件控制程式碼,該控制程式碼標識一個核心物件,如果該核心物件處於未通知狀態,則該函式導致執行緒進入阻塞狀態;如果該核心物件處於已通知狀態,則該函式立即返回WAIT_OBJECT_0。第二個引數指明瞭需要等待的時間(毫秒),可以傳遞INFINITE指明要無限期等待下去,如果第二個引數為0,那麼函式就測試同步物件的狀態並立即返回。如果等待超時,該函式返回WAIT_TIMEOUT。如果該函式失敗,返回WAIT_FAILED。可以通過下面的程式碼來判斷:

DWORD dw = WaitForSingleObject(hProcess, 5000); //等待一個程式結束
switch (dw)
{
  case WAIT_OBJECT_0:
  // hProcess所代表的程式在5秒內結束
  break;

  case WAIT_TIMEOUT:
  // 等待時間超過5秒
  break;

  case WAIT_FAILED:
  // 函式呼叫失敗,比如傳遞了一個無效的控制程式碼
  break;
}
  
還可以使用WaitForMulitpleObjects函式來等待多個核心物件變為已通知狀態:

DWORD WaitForMultipleObjects(
  DWORD dwCount, //等待的核心物件個數
  CONST HANDLE* phObjects, //一個存放被等待的核心物件控制程式碼的陣列
  BOOL bWaitAll, //是否等到所有核心物件為已通知狀態後才返回
  DWORD dwMilliseconds); //等待時間
  該函式的第一個引數指明等待的核心物件的個數,可以是0到MAXIMUM_WAIT_OBJECTS(64)中的一個值。phObjects引數是一個存放等待的核心物件控制程式碼的陣列。bWaitAll引數如果為TRUE,則只有當等待的所有核心物件為已通知狀態時函式才返回,如果為FALSE,則只要一個核心物件為已通知狀態,則該函式返回。第四個引數和WaitForSingleObject中的dwMilliseconds引數類似。

  該函式失敗,返回WAIT_FAILED;如果超時,返回WAIT_TIMEOUT;如果bWaitAll引數為TRUE,函式成功則返回WAIT_OBJECT_0,如果bWaitAll為FALSE,函式成功則返回值指明是哪個核心物件收到通知。

  可以如下使用該函式:

HANDLE h[3]; //控制程式碼陣列

//三個程式控制程式碼
h[0] = hProcess1;
h[1] = hProcess2;
h[2] = hProcess3;

DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); //等待3個程式結束

switch (dw)
{
  case WAIT_FAILED:
  // 函式呼叫失敗
  break;

  case WAIT_TIMEOUT:
  // 超時
  break;

  case WAIT_OBJECT_0 + 0:
  // h[0](hProcess1)所代表的程式結束
  break;

  case WAIT_OBJECT_0 + 1:
  // h[1](hProcess2)所代表的程式結束
  break;

  case WAIT_OBJECT_0 + 2:
  // h[2](hProcess3)所代表的程式結束
  break;
}
  
你也可以同時通知一個核心物件,同時等待另一個核心物件,這兩個操作以原子的方式進行:

DWORD SignalObjectAndWait(
  HANDLE hObjectToSignal, //通知的核心物件
  HANDLE hObjectToWaitOn, //等待的核心物件
  DWORD dwMilliseconds, //等待的時間
  BOOL bAlertable); //與IO完成埠有關的引數,暫不討論
  該函式在內部使得hObjectToSignal引數所指明的核心物件變成已通知狀態,同時等待hObjectToWaitOn引數所代表的核心物件。dwMilliseconds引數的用法與WaitForSingleObject函式類似。
  該函式返回如下:WAIT_OBJECT_0,WAIT_TIMEOUT,WAIT_FAILED,WAIT_IO_COMPLETION。

  等你需要通知一個互斥核心物件並等待一個事件核心物件的時候,可以這麼寫:

ReleaseMutex(hMutex);
WaitForSingleObject(hEvent, INFINITE);
  可是,這樣的程式碼不是以原子的方式來操縱這兩個核心物件。因此,可以更改如下:

SignalObjectAndWait(hMutex, hEvent, INFINITE, FALSE);

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25897606/viewspace-704361/,如需轉載,請註明出處,否則將追究法律責任。

相關文章