【Windows】線程漫談——線程同步之訊號量和互斥量

來源:互聯網
上載者:User

本系列意在記錄Windwos線程的相關知識點,包括線程基礎、線程調度、線程同步、TLS、線程池等

 

訊號量核心對象

訊號量核心對象用來進行資源計數,它包含一個使用計數、最大資源數、當前資源計數。最大資源數表示訊號量可以控制的最大資源數量,當前資源數表示訊號當前可用的資源數量。

設想一個情境:需要開發一個伺服器處理序,最多同時運行5個線程來響應用戶端請求,應該設計一個“線程池”。最開始的時候,5個線程都應該在等待狀態,如果有一個用戶端請求到來,那麼喚醒其中的一個線程以處理用戶端請求,如果同時的請求數量為5,那麼5個線程將全部投入使用,再多的請求應該被放棄。也就是說,隨著用戶端請求的增加,當前資源計數隨之遞減。

我們可能需要這樣的一個核心對象來實現這個功能:初始化5個線程並同時等待一個核心對象觸發,當一個用戶端請求到來時,試圖觸發核心對象,這樣5個線程中隨機一個被喚醒,並且自動使核心對象變為未觸發。外部判斷上限是否到達5。表面看來似乎用“自動重設的事件對象”即可實現這個功能啊,為什麼要涉及到訊號量呢?因為訊號量還可以控制一次喚醒多少個線程!!而且這個例子只是訊號量的一個用途,後面我們會看到一個更實際的用途。

總結一下,訊號量核心對象是這樣的一種對象:它維護一個資源計數,當資源計數大於0,處於觸發狀態;資源計數等於0時,處於未觸發狀態;資源計數不可能小於0,也絕不可能大於資源計數上限。展示了這種核心對象的特點:

如,只有資源計數>0時才是觸發狀態,資源=0時為未觸發狀態,而WaitForSingleObject成功將遞減資源計數,調用ReleaseSemaphore將增加資源計數。

下面兩個函數CreateSemaphore和CreateSemaphoreEx用於建立訊號量對象:

HANDLE WINAPI CreateSemaphore(  __in_opt  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,//核心對象安全性描述元  __in      LONG lInitialCount,//資源計數的初始值  __in      LONG lMaximumCount,//資源計數的最大值  __in_opt  LPCTSTR lpName //核心對象命名);HANDLE WINAPI CreateSemaphoreEx(  __in_opt    LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  __in        LONG lInitialCount,  __in        LONG lMaximumCount,  __in_opt    LPCTSTR lpName,  __reserved  DWORD dwFlags,  __in        DWORD dwDesiredAccess);

任何進程可以用OpenSemaphore來得到一個命名的訊號量:

HANDLE WINAPI OpenSemaphore(  __in  DWORD dwDesiredAccess,  __in  BOOL bInheritHandle,  __in  LPCTSTR lpName);

線程通過調用ReleaseSemaphore來遞增資源計數,不一定每次只遞增1,可以設定遞增任意值。當將要超過資源上限值的時候,ReleaseSemaphore會返回FALSE。

BOOL WINAPI ReleaseSemaphore(  __in       HANDLE hSemaphore,  __in       LONG lReleaseCount,//可以設定遞增的值  __out_opt  LPLONG lpPreviousCount//返回先前的資源計數);

 

互斥量核心對象

互斥量(mutex)用來確保一個線程獨佔對一個資源的訪問。互斥量包含一個使用計數、線程ID和一個遞迴計數,互斥量與關鍵段的行為幾乎相同(因為它記錄了線程ID和遞迴計數,使得互斥量可以支援遞迴調用的情況)。互斥量的規則十分簡單:如果線程ID為0(即沒有線程獨佔它),那麼它處於觸發狀態,任何試圖等待該對象的線程都將獲得資源的獨佔訪問;如果線程ID不為0,那麼它處於未觸發狀態,任何試圖等待該對象的線程都將等待。

可以使用CreateMutex或者CreateMutexEx建立互斥對象:

HANDLE WINAPI CreateMutex(  __in_opt  LPSECURITY_ATTRIBUTES lpMutexAttributes,  __in      BOOL bInitialOwner,//初始化對象的狀態,如果傳入FALSE則會初始化為觸發狀態,如果傳入TRUE,那麼對象的線程ID會被設定成當前調用線程,並初始化為未觸發  __in_opt  LPCTSTR lpName);HANDLE WINAPI CreateMutexEx(  __in_opt  LPSECURITY_ATTRIBUTES lpMutexAttributes,  __in_opt  LPCTSTR lpName,  __in      DWORD dwFlags,  __in      DWORD dwDesiredAccess);

一如既往,OpenMutex用於開啟一個已經命名的互斥量核心對象:

HANDLE WINAPI OpenMutex(  __in  DWORD dwDesiredAccess,  __in  BOOL bInheritHandle,  __in  LPCTSTR lpName);

線程在獲得對獨佔資源的存取權限之後,可以正常執行相關的邏輯,當需要釋放互斥對象的時候可以調用ReleaseMutex:

BOOL WINAPI ReleaseMutex(  __in  HANDLE hMutex);

互斥量與其他核心對象不同,它會記錄究竟是哪個線程佔用了共用資源,結合遞迴計數,同一個線程可以在獲得共用資源之後繼續訪問共用資源,這個行為就像關鍵段一樣。然而互斥量和關鍵段從本質上是不同的,關鍵段是使用者模式的線程同步方法,而互斥量是核心模式的線程同步方式。

 

介紹完這兩個核心對象後,我們思考一下前面在【Windows】線程漫談——線程同步之Slim讀/寫鎖中設計的一個情境:有一個共用的隊列,2個服務端線程負責讀取隊列中的條目以處理,2個用戶端線程負責寫入隊列中的條目以使服務先端線程處理,當隊列中沒有條目的時候應當掛起服務端線程,直到有條目進入時才被喚醒,另一方面,當隊列已滿時,用戶端線程應當掛起直到服務端至少處理了一個條目,以釋放至少一個條目的空間。

現在我們來用訊號量和互斥量來實現同樣的功能,下面的流程圖分別是用戶端寫入線程和服務端讀取線程的邏輯:

1.首先建立一個互斥量對象m_hmtxQ,並初始化為未觸發狀態;之後建立一個訊號量對象,並設定最大資源計數為隊列的長度,初始化資源計數為0,正好表徵隊列元素的個數。

m_hmtxQ = CreateMutex(NULL,FALSE,NULL);m_hsemNumElements = CreateSemaphore(NULL,0,nMaxElements,NULL);

2.設計用戶端核心邏輯如:

WatiForSingleObject:試圖獲得隊列的獨佔存取權限,對於這個隊列無論是讀還是寫都應該是線程獨佔的。因此,使用互斥量對象來同步;

ReleaseSemaphore:試圖增加一個資源計數,表徵用戶端想要向隊列中增加一個元素,當然隊列可能現在已經滿了,對應的資源計數已達到計數上限,此時ReleaseSemaphore會返回FALSE,這樣用戶端就不能像隊列中插入元素。反之,如果ReleaseSemaphore返回TRUE,表示隊列沒有滿,用戶端可以向隊列中插入元素。

ReleaseMutex:無論用戶端是否能夠像隊列中插入元素,在結束訪問後,都應該釋放互斥對象,以便其他線程能夠進入臨界資源。

3.設計服務端核心邏輯如:

WatiForSingleObject:試圖獲得隊列的獨佔存取權限,對於這個隊列無論是讀還是寫都應該是線程獨佔的。因此,使用互斥量對象來同步;

WaitForSingleObject(m_hsemNumElements…):試圖檢查訊號量對象是否是觸發狀態。只有是觸發狀態的訊號量對象,線程才能進入;也就意味著:隊列中只要有元素(資源>0,觸發狀態),服務端就能讀取。反之,如果隊列中沒有元素(資源=0,未觸發狀態),服務端將暫時不能訪問隊列,這時應該立即釋放Mutex。

ReleaseMutex:無論用戶端是否能夠像隊列中插入元素,在結束訪問後,都應該釋放互斥對象,以便其他線程能夠進入臨界資源。

 

勞動果實,轉載請註明出處:http://www.cnblogs.com/P_Chou/archive/2012/07/13/semaphore-and-mutex-in-thread-sync.html

相關文章

聯繫我們

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