秒殺多線程第八篇 經典線程同步 信號量Semaphore
前面介紹了關鍵段CS、事件Event、互斥量Mutex在經典線程同步問題中的使用。本篇介紹用信號量Semaphore來解決這個問題。
首先也來看看如何使用信號量,信號量Semaphore常用有三個函數,使用很方便。下面是這幾個函數的原型和使用說明。
第一個 CreateSemaphore
函數功能:創建信號量
函數原型:
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
);
函數說明:
第一個參數表示安全控制,一般直接傳入NULL。
第二個參數表示初始資源數量。
第三個參數表示最大並發數量。
第四個參數表示信號量的名稱,傳入NULL表示匿名信號量。
第二個 OpenSemaphore
函數功能:打開信號量
函數原型:
HANDLE OpenSemaphore(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
函數說明:
第一個參數表示訪問權限,對一般傳入SEMAPHORE_ALL_ACCESS。詳細解釋可以查看MSDN文檔。
第二個參數表示信號量句柄繼承性,一般傳入TRUE即可。
第三個參數表示名稱,不同進程中的各線程可以通過名稱來確保它們訪問同一個信號量。
第三個 ReleaseSemaphore
函數功能:遞增信號量的當前資源計數
函數原型:
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);
函數說明:
第一個參數是信號量的句柄。
第二個參數表示增加個數,必須大於0且不超過最大資源數量。
第三個參數可以用來傳出先前的資源計數,設為NULL表示不需要傳出。
註意:當前資源數量大於0,表示信號量處於觸發,等於0表示資源已經耗盡故信號量處於末觸發。在對信號量調用等待函數時,等待函數會檢查信號量的當前資源計數,如果大於0(即信號量處於觸發狀態),減1後返回讓調用線程繼續執行。一個線程可以多次調用等待函數來減小信號量。
最後一個 信號量的清理與銷毀
由於信號量是內核對象,因此使用CloseHandle()就可以完成清理與銷毀了。
在經典多線程問題中設置一個信號量和一個關鍵段。用信號量處理主線程與子線程的同步,用關鍵段來處理各子線程間的互斥。詳見代碼:
1 #include <stdio.h> 2 #include <process.h> 3 #include <windows.h> 4 long g_nNum; 5 unsigned int __stdcall Fun(void *pPM); 6 const int THREAD_NUM = 10; 7 //信號量與關鍵段 8 HANDLE g_hThreadParameter; 9 CRITICAL_SECTION g_csThreadCode; 10 int main() 11 { 12 printf(" 經典線程同步 信號量Semaphore\n"); 13 printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n"); 14 15 //初始化信號量和關鍵段 16 g_hThreadParameter = CreateSemaphore(NULL, 0, 1, NULL);//當前0個資源,最大允許1個同時訪問 17 InitializeCriticalSection(&g_csThreadCode); 18 19 HANDLE handle[THREAD_NUM]; 20 g_nNum = 0; 21 int i = 0; 22 while (i < THREAD_NUM) 23 { 24 handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); 25 WaitForSingleObject(g_hThreadParameter, INFINITE);//等待信號量>0 26 ++i; 27 } 28 WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE); 29 30 //銷毀信號量和關鍵段 31 DeleteCriticalSection(&g_csThreadCode); 32 CloseHandle(g_hThreadParameter); 33 for (i = 0; i < THREAD_NUM; i++) 34 CloseHandle(handle[i]); 35 return 0; 36 } 37 unsigned int __stdcall Fun(void *pPM) 38 { 39 int nThreadNum = *(int *)pPM; 40 ReleaseSemaphore(g_hThreadParameter, 1, NULL);//信號量++ 41 42 Sleep(50);//some work should to do 43 44 EnterCriticalSection(&g_csThreadCode); 45 ++g_nNum; 46 Sleep(0);//some work should to do 47 printf("線程編號為%d 全局資源值為%d\n", nThreadNum, g_nNum); 48 LeaveCriticalSection(&g_csThreadCode); 49 return 0; 50 }
運行結果如下圖:
可以看出來,信號量也可以解決線程之間的同步問題。
由於信號量可以計算資源當前剩余量並根據當前剩余量與零比較來決定信號量是處於觸發狀態或是未觸發狀態,因此信號量的應用範圍相當廣泛。本系列的《秒殺多線程第十篇 生產者消費者問題》將再次使用它來解決線程同步問題,歡迎大家參閱。
至此,經典線程同步問題全部結束了,下一篇《秒殺多線程第九篇 經典多線程同步問題總結》將會對其作個總結以梳理各知識點。
轉載請標明出處,原文地址:http://blog.csdn.net/morewindows/article/details/7481609
秒殺多線程第八篇 經典線程同步 信號量Semaphore