線程間的同步

線程間的同步
之前講到通過互斥對象進行線程間的同步,下面介紹其他的幾種方式來保持線程之間的同步。

一、事件對象

事件對象也屬於內核對象,包含一個使用計數,一個用於指明該事件是一個自動重置的事件還是一個人工重置的事件的布爾值,另一個用於指明該事件處於已通知狀態還是未通知狀態的布爾值。

有兩種不同類型的事件對象。一種是人工重置的事件,另一種是自動重置的事件。當人工重置的事件得到通知時,等待該事件的所有線程均變爲可調度線程當一個自動重置的事件得到通知時,等待該事件的線程中只有一個線程變爲可調度線程。

創建事件對象的函數爲CreateEvent,這個函數的功能是創建或者打開一個命名或者未命名的事件對象。
函數原型:
HANDLE WINAPI CreateEvent(
  __in          LPSECURITY_ATTRIBUTES lpEventAttributes,
  __in          BOOL bManualReset,
  __in          BOOL bInitialState,
  __in          LPCTSTR lpName
);
參數說明:
第一個參數是一個指向SECURITY_ATTRIBUTES結構的指針,確定返回的句柄是否可被子進程繼承。如果lpEventAttributes是NULL,此句柄不能被繼承。在這個地方我們可以給它傳遞NULL,讓它使用默認的安全性。
第二個參數指定是人工重置還是自動重置的事件對象被創建,如果是TRUE,表示人工重置的事件對象被創建,那麼必須用ResetEvent函數來手工將事件的狀態復原到無信號狀態。如果設置爲FALSE,當一個等待線程被釋放以後,系統將會自動將事件狀態復原爲無信號狀態。
第三個參數指定事件對象的初始狀態,如果爲TRUE,初始狀態爲有信號狀態;否則爲無信號狀態。
第四個參數是給事件對象取名字。

ResetEvent函數的功能是是把指定的事件對象設置爲無信號狀態。
函數原型:
BOOL WINAPI ResetEvent(
  __in          HANDLE hEvent
);
參數說明:參數爲事件對象的句柄。
返回值:若函數調用成功,返回值爲非0,不成功則返回值爲0。

SetEvent函數的功能是是把指定的事件對象設置爲無信號狀態。
函數原型:
BOOL WINAPI SetEvent(
  __in          HANDLE hEvent
);

參數說明:參數爲事件對象的句柄。
返回值:若函數調用成功,返回值爲非0,不成功則返回值爲0。

注意:在使用事件對象作線程間同步的時候,對於人工重置的事件對象,當它變爲有信號狀態的時候,所有的線程都可以運行。對於自動重置的事件對象,當它變爲有信號狀態的時候,所有等待該事件對象的線程只能有一個變爲可調度線程,同時操作系統會將這個事件對象設置爲非信號狀態。而人工重置的事件對象,在一個線程得到該事件對象之後呢並不會將它設置爲非信號狀態。

通過創建一個命名的事件對象,可以使一個應用程序只有一個實例運行。這個與創建一個命名的互斥對象類似。

二、關鍵代碼段(臨界區)

關鍵代碼段(臨界區)工作在用戶方式下。
關鍵代碼段(臨界區)是指一個小代碼段,在代碼能夠執行前,它必須獨佔對某些資源的訪問權。
EnterCriticalSection函數
函數原型:
void WINAPI EnterCriticalSection(
  __in_out      LPCRITICAL_SECTION lpCriticalSection
);
函數功能:等待指定臨界區對象的所有權,當被調用線程被賦予所有權的時候,函數返回。若被調用線程沒有賦予所有權的時候,那此函數一直等待,從而導致線程等待。
參數說明:指向臨界區對象的指針。
InitializeCriticalSection函數
函數原型:
void WINAPI InitializeCriticalSection(
  __out         LPCRITICAL_SECTION lpCriticalSection
);
函數功能:初始化一個臨界區對象。
LeaveCriticalSection函數
函數原型:
void WINAPI LeaveCriticalSection(
  __in_out      LPCRITICAL_SECTION lpCriticalSection
);
函數功能:釋放指定臨界區對象的所有權。
DeleteCriticalSection函數
函數原型:
void WINAPI DeleteCriticalSection(
  __in_out      LPCRITICAL_SECTION lpCriticalSection
);
函數功能:釋放一個沒有被擁有的臨界區對象的所有的相關資源。

通過調用上面這四個函數可以利用臨界區對象實現線程之間的同步。

線程死鎖

線程1擁有了臨界區對象A,等待臨界區對象B的擁有權,線程2擁有了臨界區對象B,等待臨界區對象A的擁有權,就造成了死鎖。

互斥對象、事件對象與關鍵代碼段的比較

互斥對象和事件對象屬於內核對象,利用內核對象進行線程同步,速度較慢,但利用互斥對象和事件對象這樣的內核對象,可以在多個進程中的各個線程間進行同步。
關鍵代碼段是工作在用戶方式下,同步速度較快,但在使用關鍵代碼段時,很容易進入死鎖狀態,因爲在等待進入關鍵代碼段時無法設定超時值。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章