windows多線程(八) 信號量Semaphore


如果你看到了這里,我就認為你已經對掌握了有關關鍵段 CriticalSection、互斥量Mutex和事件Event有關的內容,所以最基本的東西就不再介紹了。如果沒有掌握上面說的內容,可以看這里:

  1. 關鍵段 CriticalSection
  2. 互斥量Mutex
  3. 事件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;
}

運行結果如下所示:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM