如果你看到了這里,我就認為你已經對掌握了有關關鍵段 CriticalSection、互斥量Mutex和事件Event有關的內容,所以最基本的東西就不再介紹了。如果沒有掌握上面說的內容,可以看這里:
一、信號量相關函數說明
(一) 創建信號量CreateSemaphore
1.函數原型
HANDLE WINAPI CreateSemaphore(
_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
_In_ LONG lInitialCount,
_In_ LONG lMaximumCount,
_In_opt_ LPCWSTR lpName
);
2.參數說明
-
第一個參數
lpSemaphoreAttributes
,表示安全屬性。如果是NULL,就表示使用默認屬性。 -
第二個參數
lInitialCount
,信號量的初始數值,必須大於或等於0,並且小於或等於lMaximumCount -
第三個參數
lMaximumCount
,信號量的最大值,即最大並發數。 -
第四個參數
lpName
,信號量的名字,是一個字符串,任何線程(或進程)都可以根據這一名稱引用到這個信號量,這個值可以是NULL,表示產生一個匿名信號量。 -
返回值: 如果成功就返回一個handle,否則傳回NULL。
(二) 打開信號量OpenSemaphore
1.函數原型
HANDLE WINAPI OpenSemaphore(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ LPCSTR lpName
);
2.參數說明
-
第一個參數
dwDesiredAccess
,表示訪問權限,一般傳入SEMAPHORE_ALL_ACCESS。 -
第二個參數
bInheritHandle
,表示信號量句柄繼承性,一般傳入True。 -
第三個參數
lpName
,需要打開的信號量的名稱。 -
返回值: 如果成功就返回信號量handle,否則傳回NULL。
(三) 信號量解除鎖定ReleaseSemaphore
這個函數功能是實現信號量計數器增加一個值,該值通常是1,但不會超過創建信號量時指定的lMaximumCount
1.函數原型
BOOL WINAPI ReleaseSemaphore(
_In_ HANDLE hSemaphore,
_In_ LONG lReleaseCount,
_Out_opt_ LPLONG lpPreviousCount
);
2.參數說明
-
第一個參數
hSemaphore
,信號量的句柄。 -
第二個參數
lReleaseCount
,表示信號量值增加的個數,必須大於0且不超過最大資源數,一般為1。 -
第三個參數
lpPreviousCount
,傳出先前信號量的計數值,設置為NULL表示不需要傳出。 -
返回值: 如果成功就返回True,否則傳回False。
(四) 關閉信號量
由於信號量是一個內核對象,關閉時直接調用CloseHandle()
就可以了。
二、實例
使用信號量同樣可以實現線程的同步,實現每個線程按順序依次給全局資源加一,代碼如下:
// 信號量演示
#include<iostream>
#include <windows.h>
using namespace std;
const int THREAD_NUM = 10;
int g_Num = 0;
CRITICAL_SECTION g_csVar; //創建關鍵段cs
HANDLE g_ThreadSema; //創建內核對象,用來初始化信號量
DWORD WINAPI Func(LPVOID);
int main()
{
InitializeCriticalSection(&g_csVar);
g_ThreadSema = CreateSemaphore(NULL, 0, 1, NULL); //創建匿名信號量,初始資源為零,最大並發數為1,
HANDLE handle[THREAD_NUM];
DWORD ThreadId[THREAD_NUM];
int i = 0;
while (i < THREAD_NUM)
{
handle[i] = CreateThread(NULL, 0, Func, &i, 0, &ThreadId[i]);
WaitForSingleObject(g_ThreadSema, INFINITE); //等待信號量資源數>0
i++;
}
WaitForMultipleObjects(THREAD_NUM, handle, true, INFINITE);
CloseHandle(g_ThreadSema); //銷毀信號量
DeleteCriticalSection(&g_csVar);//銷毀關鍵段cs
for (i = 0; i < THREAD_NUM; i++)
{
CloseHandle(handle[i]);
}
return 0;
}
DWORD WINAPI Func(LPVOID p)
{
int nThreadNum = *(int*)p;
EnterCriticalSection(&g_csVar);
cout << "線程編號為: " << nThreadNum << " 全局資源值為:" << ++g_Num << endl;
LeaveCriticalSection(&g_csVar);
ReleaseSemaphore(g_ThreadSema, 1, NULL); //信號量資源數加一
return 0;
}
運行結果如下所示: