C++ 临界区、信号量简单介绍

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/llmys/article/details/82315466

生产者-消费者模式中会用到信号量进行同步。比如多个生产者线程产生的消息放置在一个链表中或者一个环形缓冲区中,消费者线程从链表或者环形缓冲区去读取消息。这个时候需要用到信号量和临界区。

下面介绍一下信号量和临界区

信号量:

// 创建信号量,函数返回值:信号量的句柄
HANDLE CreateSemaphore(
  // 安全控制,一般传入NULL
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,	
  // 初始化时,拥有的资源数量
  LONG                  lInitialCount,			
  // 能够拥有的最大的资源数量
  LONG                  lMaximumCount,			
  // 信号量的名字
  LPCSTR                lpName					
);

// 等待信号量变为有信号状态
DWORD WaitForSingleObject(
  // 等待信号量的句柄
  HANDLE hHandle,								
  // 等待的时间;传入0,直接返回不等待;传入整数,在整数时间内有信号就返回,无信号超时返回;  INFINITE,一直等待,直到有信号
  DWORD  dwMilliseconds
);

// 增加信号量信号计数
BOOL ReleaseSemaphore(
  // 信号量的句柄
  HANDLE hSemaphore,							
  // 信号量计数需要增加的数目,必须大于0
  LONG   lReleaseCount,
  // 用于接收之前信号量数量的指针    
  LPLONG lpPreviousCount						
);

用法示例:

// 创建信号量
HANDLE hSemaphore = CreateSemaphore(NULL, 0, 1000, NULL);
// 等待信号量变为有信号状态,调用该函数后信号量的计数减1
WaitForSingleObject(hSemaphore, INFINITE);
// 当消息来临时,增加信号量的计数
ReleaseSemaphore(hSemaphore, 1, NULL);

临界区

// 初始化临界区
VOID InitializeCriticalSection(
  // 传入临界区对象
  LPCRITICAL_SECTION lpCriticalSection			
);

// 加锁 接下来的代码处理过程中不允许其他线程进行操作,除非遇到LeaveCriticalSection将临界区资源释放
VOID EnterCriticalSection(
	LPCRITICAL_SECTION lpCriticalSection
);

// 释放临界区资源,使其他线程可以使用EnterCriticalSection访问临界区资源
void LeaveCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);
// 释放临界区对象使用的所有系统资源
void DeleteCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

用法示例:

// 用法示例
InitializeCriticalSection(&cs);//初始化临界区
EnterCriticalSection(&cs);//进入临界区
// 需要进行的业务操作
LeaveCriticalSection(&cs);//离开临界区
DeleteCriticalSection(&cs);//删除临界区

临界区信号量小例子

#include <iostream>
using namespace std;
#include <stdlib.h>
#include <Windows.h>

struct  Node
{
	int num;
	Node* pNext;

	static Node* NewNode(int num)
	{
		Node* pNode = (Node*)malloc(sizeof(Node));
		pNode->num = num;
		pNode->pNext = NULL;
		return pNode;
	}
};

Node* pHead = Node::NewNode(0);
CRITICAL_SECTION g_cs;
HANDLE hSemaphore = NULL;
void AddNode(int num) 
{
	EnterCriticalSection(&g_cs);
	Node* pTemp = Node::NewNode(num);
	Node* pMove = pHead;
	while (pMove)
	{
		if (pMove->pNext == NULL)
		{
			pMove->pNext = pTemp;
			cout << "增加一个产品:" << num << endl;
			ReleaseSemaphore(hSemaphore, 1, NULL);
			break;
		} 
		else
		{
			pMove = pMove->pNext;
		}
	}
	LeaveCriticalSection(&g_cs);
	Sleep(1);
}


void DelNode()
{
	WaitForSingleObject(hSemaphore, INFINITE);
	EnterCriticalSection(&g_cs);
	Node* pTemp = pHead->pNext;
	if (pTemp != NULL)
	{
		cout<< "线程号:[" <<GetCurrentThreadId() << "],删除节点:" << pTemp->num << endl;
		pHead->pNext = pTemp->pNext;
		delete pTemp;
	}
	LeaveCriticalSection(&g_cs);	
}


DWORD WINAPI DeleteThread(LPVOID args)
{
	while (true)
	{
		DelNode();
		Sleep(1);
	}
	return 0;
}

int main()
{
	InitializeCriticalSection(&g_cs);
	hSemaphore = CreateSemaphore(NULL, 0, 1000, NULL);
	HANDLE hThread1 = CreateThread(NULL, 0, DeleteThread, NULL, 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, DeleteThread, NULL, 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, DeleteThread, NULL, 0, NULL);
	HANDLE hThread4 = CreateThread(NULL, 0, DeleteThread, NULL, 0, NULL);
	HANDLE hThread5 = CreateThread(NULL, 0, DeleteThread, NULL, 0, NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);
	CloseHandle(hThread4);
	CloseHandle(hThread5);	
	int count = 1;
	while (true)
	{
		int num ;
		cin >> num;
		if (num == 0)
			break;
		for (int i = 0; i < num; i++)
		{
			AddNode(count);
			count++;
		}
	}
	DeleteCriticalSection(&g_cs);
    return 0;
}

运行结果:

10
增加一个产品:1
线程号:[11988],删除节点:1
增加一个产品:2
线程号:[9420],删除节点:2
增加一个产品:3
线程号:[13064],删除节点:3
增加一个产品:4
线程号:[3368],删除节点:4
增加一个产品:5
线程号:[12212],删除节点:5
增加一个产品:6
线程号:[11988],删除节点:6
增加一个产品:7
线程号:[9420],删除节点:7
增加一个产品:8
线程号:[13064],删除节点:8
增加一个产品:9
线程号:[3368],删除节点:9
增加一个产品:10
线程号:[12212],删除节点:10

猜你喜欢

转载自blog.csdn.net/llmys/article/details/82315466