《Windows via C/C++》學習筆記 —— 使用者模式的“線程同步”之“條件變數”

來源:互聯網
上載者:User

  Condition variables —— 條件變數,是Windows Vista中新增加的一種處理線程同步問題的機制。它可以與“關鍵程式碼片段(critical section)”或“讀寫鎖(SRWLock)”相互配合使用,來實現線程的同步,特別是實作類別似“生產者-消費者”問題的時候,十分有效。

  如果當前沒有“產品”可供“消費者線程”(讀者線程)使用,那麼該“消費者線程”要釋放掉對應的讀寫鎖或者關鍵程式碼片段,然後等待直到有一個新的“產品”被“生產者線程”(寫者線程)製造出來之後,方可繼續運行。

  如果一個用來存放“產品”的資料結構滿了(比如數組),那麼對應“生產者線程”需要釋放有關的鎖和關鍵程式碼片段,同時要等待“消費線程者”消費完這些“產品”。

 

  條件變數機制就是為了簡化上述“生產者-消費者”問題而設計的一種線程同步機制。當一個線程需要以原子的方式釋放加在資源上的鎖,並且需要被阻塞運行直到一個條件被滿足,你可以呼叫如下的函數:

BOOL SleepConditionVariableCS(
   PCONDITION_VARIABLE pConditionVariable,
   PCRITICAL_SECTION pCriticalSection,
   DWORD dwMilliseconds);BOOL SleepConditionVariableSRW(
   PCONDITION_VARIABLE pConditionVariable,
   PSRWLOCK pSRWLock,
   DWORD dwMilliseconds,
   ULONG Flags);

 

  正如函數名所預示的那樣,第一個函數針對關鍵程式碼片段,第二個函數針對讀寫鎖。

  第1個參數pContidionVariable參數指向一個初始化的條件變數,該條件變數指明了調用者(一個線程)的條件變數,參數類型是CONDITION_VARIABLE的指標。

  第2個參數指明了一個“關鍵程式碼片段”或“讀寫鎖”,它們是用來保護共用資源的。

  第3個參數dwMilliseconds指明了你的線程想要等待多長時間,你可以傳遞INFINITE,指明需要無限期等待下去。

  第二個函數的第4個參數Flags指明當條件變數滿足的時候,你需要對應的鎖做如何的要求(即返回的時候設定鎖,該鎖應該是什麼類型的):在“生產者線程”(寫者線程)中你應該傳遞0給該參數指明該鎖是一個“獨佔鎖定”,該鎖被線程獨佔;在“消費者線程”(讀者線程)中你應該傳遞CONDITION_VARIABLE_LOCKMODE_SHARED給該參數指明該鎖是一個“共用鎖定”,該鎖能以共用的方式為“消費者線程”服務。

  在該參數調用的時候,第二個參數所指定的關鍵程式碼片段或讀寫鎖會被釋放,使得對應的線程可以訪問共用資源,從而去“生產”或“消費”;在該函數返回的時候,這個鎖又會被設定。如果是SRWLock,該函數返回的時候根據Flags參數設定讀寫鎖類型:獨佔鎖定或共用鎖定。關鍵程式碼片段則會被自動化佈建,因為關鍵程式碼片段總是“排他”的。

  如果等待逾時,該函數返回FALSE,否則返回TRUE。

 

  一個線程當被SleepConditionVariableCS或SleepConditionVariableSRW阻塞之後,可以被另一個線程通過呼叫WakeConditionVariable或WakeAllConditionVariable函數喚醒。

VOID WakeConditionVariable(
   PCONDITION_VARIABLE ConditionVariable);     //條件變數指標VOID WakeAllConditionVariable(
   PCONDITION_VARIABLE ConditionVariable);     //條件變數指標

 

  當你呼叫WakeConditionVariable函數的時候,傳遞一個條件變數的指標給它,此時,在一個等待在同樣條件變數的上的線程的SleepConditionVariable函數內部,條件變數收到訊號,通知線程,該函數會返回,同時把對應的鎖設定為所需要的類型。

  當你呼叫WakeAllConditionVarialbe函數的時候,一個過多個等待在相同條件變數上的線程會被被喚醒。喚醒多個線程是可以的,但是你需要在調用SleepConditionVariable*函數的時候設定參數Flags:給“生產者線程”傳遞0;給“消費者線程”傳遞CONDITION_VARIABLE_LOCKMODE_SHARED。所以,有些時候,“消費者線程”全部會被喚醒。或者這樣喚醒:生產者、消費者、生產者、消費者……如此迴圈。

 

  本書還舉了一個例子,這裡就不多說了,我個人總結了下,運用條件變數應該遵循如下模式(自己是這麼認為的,如果有誤還大家請指出)

 

CONDITION_VARIABLE g_cvProduce;   //生產條件變數
CONDITION_VARIABLE g_cvConsume;   //消費條件變數
SRWLOCK g_srwLock;     //讀寫鎖

DWORD WINAPI Consumer(PVOID pvParam)     //消費者線程函數
{
     
     AcquireSRWLockShard(&g_srwLock);     //請求共用鎖定(讀鎖)
     SleepConditionVariableSRW(g_cvConsume, &g_srwLock, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);    //等待條件變數,會被生產者線程喚醒

          //消費

     ReleaseSRWLockShared(&g_srwLock);     //釋放共用鎖定
     WakeConditionVariable(&g_cvProduce);     //喚醒一個生產者線程
     
}

DWORD WINAPI Producer(PVOID pvParam)     //生產者線程函數
{
     
     AcquireSRWLockExclusive(&g_srwLock);     //要求一個獨佔鎖定(寫鎖)

 

     //等待條件變數受信,會被消費者線程喚醒
     SleepConditionVariableSRW(g_cvProduce, &g_srwLock, INFINITE, 0);

          //生產

     ReleaseSRWLockExclusive(&g_srwLock);     //釋放獨佔鎖定
     WakeAllConditionVariable(&g_cvConsume);  //喚醒所有消費者線程
     
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.