標籤:
一、前言
之前在項目中,由於需要使用到多線程,多線程能夠提高執行的效率,同時也帶來線程同步的問題,故特此總結如下。
二、windows線程同步機制
windows線程同步機制常用的有幾種:Event、Critical Section、Mutex、Semaphore。
1.Critical Section(臨界區)
適用範圍: 單一進程的各線程之間用來排它性佔有
特性: 不是核心對象,是這裡提到的四種機制中速度效率最高的(注意:由於臨界區是非核心對象,可在使用者空間維護,則無控制代碼,那麼就不能使用WaitForMultipleObjects防止死結的問題了)。無法監測是否被線程放棄。如果在Critical Sections中間突然程式crash或是exit而沒有調用LeaveCriticalSection,則結果是該線程所對應的核心不能被釋放,該線程成為死線程。
臨界區相關函數:
1 VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); //函數功能初始化一個臨界資來源物件。2 VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 進入臨界區3 VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 離開臨界區4 VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 銷毀臨界區
2.Mutex(互斥核心對象)
適用範圍: 不同線程之間用來排它性佔有
特性: 核心對象,有控制代碼,有擁有者,哪個線程擁有mutex,就佔有mutex的所有權,非擁有者執行ReleaseMutex會出錯。mutex可以跨進程同步。
互斥量相關函數:
a.建立
1 HANDLE CreateMutex(2 LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全屬性結構指標3 BOOL bInitialOwner, //是否佔有該互斥量4 LPCTSTR lpName //設定互斥對象的名字5 );
b.開啟一個現有命名互斥量
1 HANDLE OpenMutex(2 DWORDdwDesiredAccess, // access3 BOOLbInheritHandle, // inheritance option4 LPCTSTRlpName // object name5 );
c.佔有/擷取互斥量
1 DWORD WaitForSingleObject(2 HANDLE hHandle,3 DWORD dwMilliseconds4 );
d.釋放互斥量
1 BOOL WIANPI ReleaseMutex(2 HANDLE hMutex3 );
3.Event(事件核心對象)
適用範圍: 用來控制對象訊號的接收,常與訊號系統結合起來
特性: 核心對象,有控制代碼,有兩種不同類型的事件對象。一種是人工重設的事件,另一種是自動重設的事件。當人工重設的事件得到通知時(signaled),等待該事件的所有線程均變為可調度線程,直到調用ResetEvent,事件才會變為unsignaled。當一個自動重設的事件得到通知時,等待該事件的線程中只有一個線程變為可調度線程,事件則自動變為unsigned。
SetEvent後,自動置位事件則會保持狀態,直到有等待事件的,之後自動複位。手動複位事件,則儲存signaled狀態直到調用ResetEvent。
PulseEvent後,對於手動複位事件,所有當前線程(如果有的話)會得到釋放,而後事件會被複位為unsigned。(不建議使用)
WaitForMultipleObjects,只有當所有等待的事件同時處於signaled,才會釋放,對於自動複位的事件線上程釋放後自動複位。
相關函數:CreateEvent, OpenEvent,SetEvent, ResetEvent, PulseEvent。
4.Semaphore(訊號核心對象)
適用範圍: 用來限制資源佔用
特性: 核心對象,沒有擁有者,任何線程都可釋放。訊號量(Semaphore)核心對象對線程的同步方式與前面幾種方法不同,它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數目。在用 CreateSemaphore()建立訊號量時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設定為最大資源計數,每增加一個線程對共用資源的訪問,當前可用資源計數就會減1,只要當前可用資源計數是大於0的,就可以發出訊號量訊號。但是當前可用計數減小到0時則說明當前佔用資源的線程數已經達到了所允許的最大數目,不能在允許其他線程的進入,此時的訊號量訊號將無法發出。線程在處理完共用資源後,應在離開的同時通過 ReleaseSemaphore()函數將當前可用資源計數加1。在任何時候當前可用資源計數決不可能大於最大資源計數。
函數: CreateSemaphore OpenSemaphore ReleaseSemaphore
三、對比Mutex與Critical Section對比
1.Mutex如果被終止線程所泛起,會是已傳信的,其他線程不會永遠阻塞;而Critical Section則不是,如果被終止線程沒有釋放,那麼其他等待線程將永遠阻塞。
2.Mutex是核心對象,,有逾時機制(有控制代碼,可以是使用WaitFor_函數實現);而CS非核心對象,無控制代碼,不能使用WaitFor系列函數,實現逾時機制,只能使用TryEnterCriticalSection輪詢。
3.Mutex可命名,可以跨進程同步,CS不行。
4.Mutex可在建立時,立即指定對該mutex的擁有權,CS沒有不行。
5.CS由於是非核心對象,不需要頻繁的切換程式啟動並執行狀態到核心態下,所有CS幾乎總是比Mutex要快。
非核心對象(CS)與核心對象(其他的)對比:
1.核心對象有控制代碼能使用WaitForMultipleObjects,一次等待多個對象,避免死結;
2.CS無控制代碼,不能使用,需要自己考慮防止死結的問題。(給CS編號,按照一定順序擷取,打破形成環)。
3.對於上面幾種命名的核心同步對象,可以進行跨進程同步;而,CS是非核心對象,直接建構在使用者空間下,速度快的同時帶來另一個問題,那就是沒有辦法跨進程同步。
四、後記
對於CS的使用,我們一般使用內部類的形式,防止異常的時候沒有LeaveCriticalSection。
這個可能總結不夠全,希望以後能夠進行總結。另外該博文參考了http://www.cnblogs.com/luxiaoxun/archive/2012/10/10/2717765.html
windows線程同步