《Windows via C/C++》學習筆記 —— 核心對象的“線程同步”之“事件核心對象”

來源:互聯網
上載者:User

  本書首先介紹了一個重要的概念“成功的副作用”,這裡筆者作一下簡述。

  當調用WaitForSingleObject和WaitForMultipleObject函數成功之後,該函數在返回成功的時候,系統可能會自動更改所等待的核心對象的狀態,即將其從“已通知狀態”切換為“未通知狀態”。

  當一個核心對象的狀態被更改,稱之為“成功等待的副作用”。比如,一個“自動重設”的事件核心對象,當調用等待函數成功返回的時候,該事件核心對象會由已通知狀態轉變為未通知狀態。

  比如此時有一個自動重設的事件核心對象hEvent,它處於未通知狀態。線程T1、T2、T3內部調用“WaitForSingleObject(hEvent, INFINITE);”,這樣當該事件核心對象變為“已通知”狀態的話,T1線程“可能”被喚醒,但是其他的線程T2和T3呢?由於在T1線程內部WaitForSingleObject函數返回成功,又將hEvent事件核心對象設定為“未通知”狀態,那麼T2和T3就不可能被喚醒。

  也就是說,“成功等待的副作用”會導致多個等待在同一個核心對象上的線程只能被喚醒一個。

 

  好,下面我們來討論“事件核心對象”。

  在所有核心對象中,事件核心對象是最基本的一個核心對象。在事件核心對象內部,有以下幾個比較重要的資料:

1、有一個“引用計數”:指明被開啟的次數;

2、一個“布爾值”:指明該事件核心對象是自動重設的還是人工重設的;

3、另一個“布爾值”:指明該事件核心對象是“已通知狀態”還是“未通知狀態”。

  事件核心對象可以通知一個事件已經完成。有兩種不同的類型:自動重設和人工重設。當人工重設的事件核心對象得到通知的時候,所有等待在事件核心對象上的線程都變成可調度線程。當一個自動重設的事件核心對象得到通知的時候,等待在該事件核心對象上的線程只有一個能變成可調度狀態。

 

  要使用事件核心對象,首先調用CreateEvent函數來建立一個事件核心對象:

HANDLE CreateEvent(
   PSECURITY_ATTRIBUTES psa,
   BOOL bManualReset,
   BOOL bInitialState,
   PCTSTR pszName);

 

  參數psa是一個SECURITY_ATTRIBUTES(安全屬性)結構的指標,一般設定為預設安全,傳遞NULL。

  bManualReset參數指定了該核心對象是人工重設(傳遞TRUE)的還是自動重設(傳遞FALSE)的。

  bInitialState參數指定了該核心對象起始狀態是已通知(傳遞TRUE)還是未通知狀態(FALSE)。

  pszName參數為要建立的事件核心對象起一個名字,如果傳遞NULL,則建立一個“匿名”的事件核心對象。如果不傳遞NULL,且系統中已經存在該名字的事件核心對象,則不建立新的事件核心對象而是開啟這個已經存在的,返回它的控制代碼。

  該函數如果成功,返回事件核心對象的控制代碼,這樣就可以操縱它了。如果失敗,返回NULL。

 

  Windows Vista提供了另一個函數來建立事件核心對象:

HANDLE CreateEventEx(
   PSECURITY_ATTRIBUTES psa,
   PCTSTR pszName,
   DWORD dwFlags,
   DWORD dwDesiredAccess);

 

  該函數的psa和pszName參數的意義和函數CreateEvent相同。

  參數dwFlags可以有以下資料的“位或組合”:

WinBase.h中定義的位組合資料 

描述 

CREATE_EVENT_INITIAL_SET (0x00000002)

如果設定了該資料,則表明事件核心對象的起始狀態為已通知狀態;否則起始狀態為未通知狀態。

CREATE_EVENT_MANUAL_RESET (0x00000001)

如果設定了該資料,則表明事件核心對象是人工重設的;否則為自動重設的。

  參數dwDesiredAccess可以讓你對該事件核心對象的訪問加一些限制,本書沒有細說,查MSDN就可以了吧。

 

  可以開啟一個“命名”的事件核心對象:

HANDLE OpenEvent(
   DWORD dwDesiredAccess,
   BOOL bInherit,
   PCTSTR pszName);

 

  第一個參數指明的訪問的限制,第二個參數表示該事件核心對象的控制代碼能夠被子進程繼承,第三個參數指明了該事件核心對象的名字。該函數成功返回事件核心對象的控制代碼,失敗返回NULL。

  當不需要使用這些控制代碼時,需要調用CloseHandle函數來遞減核心對象的引用計數,使得該核心對象可以被及時清除。

 

  當一個事件核心對象被建立之後,你可以直接控制它的狀態。你可以通知它,使得它從未通知狀態轉變為已通知狀態: 

BOOL SetEvent(HANDLE hEvent);

 

  也可以重新設定它,使它從已通知狀態變為未通知狀態:

BOOL ResetEvent(HANDLE hEvent);

 

  一個自動重設的事件核心對象,如果等待成功,由於“成功等待的副作用”機制會將該事件核心對象由已通知狀態變為未通知狀態,這個時候就沒有必要調用ResetEvent函數了。

  如果是一個人工重設的事件核心對象,等待成功之後,並不會被設定為未通知狀態,而是要程式員調用ResetRvent函數來使之轉變為未通知狀態。

 

  還有要注意的就是,一個“自動重設”的事件核心對象收到通知,轉變為已通知狀態的時候,最多隻能喚醒“一個”等待在它上的線程。一個“人工重設”的事件核心對象收到通知,轉變為已通知狀態的時候,能夠喚醒“所有”等待在它上的線程。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.