以一個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛直接進入,然后放下車攔,剩下的車則必須在入口等待,此后來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知后,打開車攔,放入外面的一輛進去,如果又離開兩輛,則又可以放入兩輛,如此往復。
在這個停車場系統中,車位是公共資源,每輛車好比一個線程,看門人起的就是信號量的作用。
抽象的來講,信號量的特性如下:信號量是一個非負整數(車位數),所有通過它的線程/進程(車輛)都會將該整數減一(通過它當然是為了使用資源),當該整數值為零時,所有試圖通過它的線程都將處於等待狀態。在信號量上我們定義兩種操作: Wait(等待) 和 Release(釋放)。當一個線程調用Wait操作時,它要么得到資源然后將信號量減一,要么一直等下去(指放入阻塞隊列),直到信號量大於等於一時。Release(釋放)實際上是在信號量上執行加操作,對應於車輛離開停車場,該操作之所以叫做“釋放”是因為釋放了由信號量守護的資源。
可以用信號量實現主線程與子線程間的同步,而用關鍵段實現子進程間的互斥:
第一個 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()就可以完成清理與銷毀了。
#include<stdio.h> #include<process.h> #include<windows.h> volatile long g_nLoginCount; const int THREAD_NUM = 10; volatile long g_num; CRITICAL_SECTION g_thread; HANDLE g_Semaphore; //信號量 unsigned int __stdcall ThreadFun(void *pPM){ int thread_id=*((int *)pPM); ReleaseSemaphore(g_Semaphore,1,NULL);//信號量++ Sleep(50); EnterCriticalSection(&g_thread); g_num++; Sleep(0); printf("ID : %d 全局:%d\n",thread_id,g_num); LeaveCriticalSection(&g_thread); return 0; } int main(){ InitializeCriticalSection(&g_thread); g_Semaphore = CreateSemaphore(NULL,0,1,NULL);//當前0個資源,最大允許1個同時訪 g_nLoginCount = 0; g_num=0; HANDLE handle[THREAD_NUM]; int num=20; g_nLoginCount = 0; for(int i = 0;i < THREAD_NUM; i++){ handle[i] = (HANDLE)_beginthreadex(NULL,0,ThreadFun,&i,0,NULL); WaitForSingleObject(g_Semaphore,INFINITE); } WaitForMultipleObjects(THREAD_NUM,handle,TRUE,INFINITE); CloseHandle(g_Semaphore); DeleteCriticalSection(&g_thread); return 0; }
總結:信號量與事件的區別在與,信號量的大小可以設置,而事件可以看做是“大小為1的信號量”。
參考:http://blog.csdn.net/morewindows/article/details/7481609