C++11多线程:windows临界区和Linux互斥锁、递归锁的区别与使用。

news2024/11/26 22:20:32

文章目录

  • 前言
  • 一、windows临界区
    • 1.1 基本概念
    • 1.2 函数使用
  • 二、使用步骤
    • 1.代码示例1
  • 总结


前言

多线程windows临界区和Linux互斥锁


提示:以下是本篇文章正文内容,下面案例可供参考

一、windows临界区

1.1 基本概念

Linux下有递归锁,递归锁是同一个线程在不解锁的情况下,可以多次获取锁定同一个递归锁,而且不会产生死锁。windows下的互斥量和临界区(关键段)默认支持递归锁。

  • 在windows临界区,同一个线程(不同线程就会卡住等待)中,
  • windows中的“相同临界区变量”代表的临界区的进入(EnterCriticalSection)可以被多次调用。而在c++11中,不允许 同一线程中lock同一个互斥量多次,否则报异常。
  • 但是你调用了几次EnterCriticalSection,你就得调用几次LeaveCriticalSection(&my_winsec);

1.2 函数使用

(1)windows临界区

//初始化一个临界区对象
void InitializeCriticalSection(  LPCRITICAL_SECTION lpCriticalSection);
//删除临界区对象释放由该对象使用的所有系统资源
void DeleteCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);
//进入临界区,相当于Linux下lock
void EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection );
//删除临界区,相当于Linux下unlock
void LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection );

(2)其他:linux递归锁和互斥锁

//自动析构技术
std::lock_guard<std::mutex>
lock()
unlock();

二、使用步骤

1.代码示例1

把类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection导致死锁情况的发生,类似于c++11中的std::lock_guardstd::mutex

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <list>
#include <mutex>
#include <future>
#include <windows.h>

using namespace std;

//#define __WINDOWSJQ_

//把类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection导致死锁情况的发生,类似于c++11中的std::lock_guard<std::mutex>
class CWinLock	//叫RAII类(Resource Acquisition is initialization)中文“资源获取即初始化”
					//容器,智能指针这种类,都属于RAII类
{
public:
	CWinLock(CRITICAL_SECTION *pCritmp)	//构造函数
	{
		m_pCritical = pCritmp;
		EnterCriticalSection(m_pCritical);
	}

	~CWinLock()	//析构函数
	{
		LeaveCriticalSection(m_pCritical);
	}

private:
	CRITICAL_SECTION *m_pCritical;
};

class A
{
public:
	//把收到的消息到队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;

#ifdef __WINDOWSJQ_
			//EnterCriticalSection(&my_winsec);	//进入临界区(加锁)
			//EnterCriticalSection(&my_winsec);
			CWinLock wlock(&my_winsec);		//wlock,wlock2 都属于RAII对象。
			CWinLock wlock2(&my_winsec);	//调用多次也没问题;
			msgRecvQueue.push_back(i);
			//LeaveCriticalSection(&my_winsec);	//离开临界区(解锁)
			//LeaveCriticalSection(&my_winsec);
#else
			//my_mutex.lock();
			//my_mutex.lock();	//报异常,和windows有区别;
			std::lock_guard<std::mutex> sbguard(my_mutex);
			//std::lock_guard<std::mutex> sbguard1(my_mutex);
			msgRecvQueue.push_back(i);	//假设这个数字i就是我收到的命令,我直接弄到消息队列里边来;
			//my_mutex.unlock();
			//my_mutex.unlock();
#endif
		}
	}

	bool outMsgLULProc(int &command)
	{
#ifdef __WINDOWSJQ_
		EnterCriticalSection(&my_winsec);
		if (!msgRecvQueue.empty())
		{
			command = msgRecvQueue.front();	//返回第一个元素但不检查元素存在与否
			msgRecvQueue.pop_front();
			LeaveCriticalSection(&my_winsec);
			return true;
		}
		LeaveCriticalSection(&my_winsec);// 可多次调用
#else
		my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			command = msgRecvQueue.front();	//返回第一个元素但不检查元素存在与否
			msgRecvQueue.pop_front();
			my_mutex.unlock();
			return true;
		}
		my_mutex.unlock();// 可多次调用
#endif

		return false;
	}

	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100; ++i)
		{
			bool result = outMsgLULProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << command << endl;
				//这里可以考虑处理数据
				//.....
			}
			else
			{
				cout << "outMsgEecvQueue()执行,但目前消息队列中为空" << i << endl;
			}
		}
		cout << "end" << endl;
	}

	A()
	{
#ifdef __WINDOWSJQ_
		InitializeCriticalSection(&my_winsec);	//用临界区之前要先初始化
#endif
	}


private:
	std::list<int> msgRecvQueue;	//容器,专门用于代表玩家给咱们发送过来的命令
	std::mutex my_mutex;	//创建互斥量

#ifdef __WINDOWSJQ_
	CRITICAL_SECTION my_winsec;	//windows种的临界区,非常类似于C++11种的mutex
#endif
};

int main()
{
	//一:windows临界区
	//二:多次进入临界区试验
	//在同一个线程(不同线程就会卡住等待)中,windows中的“相同临界区变量”代表的临界区的进入(EnterCriticalSection)可以被多次调用
		//但是你调用了几次EnterCriticalSection,你就得调用几次LeaveCriticalSection(&my_winsec);
		//而在c++11中,不允许 同一线程中lock同一个互斥量多次,否则报异常

	//三:自动析构技术
	//std::lock_guard<std::mutex>

	//四:recursive_mutex递归的独占互斥量

	A myobja;
	std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja);	//注意这里第二个参数必须时引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
	
	myOutnMsgObj.join();
	cout << "myOutnMsgObj  end!" << endl;
	myInMsgObj.join();
	cout << "myInMsgObj  end!" << endl;
	

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述


总结

(1)了解windows临界区;
(2)了解linux递归锁和互斥锁;
(3)了解基本函数的使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/525139.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

着重讲解一下自动化测试框架的思想与构建策略,让你重新了解自动化测试框架

目录 序言&#xff1a; 一、简述自动化测试框架 二、自动化测试框架思想 三、构建自动化测试框架的策略 四、自动化测试框架的发展趋势 序言&#xff1a; 也许到现在大家对所谓的“自动化测试框架”仍然觉得是一种神秘的东西&#xff0c;仍然觉得其与各位很远&#xff1b;…

【JavaScript】ES6新特性(1)

1. let 声明变量 let 声明的变量只在 let 命令所在的代码块内有效 块级作用域 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge">&l…

08-04 中间件和平台运行期监控

缓存中间件的三大坑 缓存击穿 用户访问热点数据&#xff0c;并且缓存中没有热点数据&#xff0c;大量访问直接到DB&#xff0c;热点击穿采用Canal做数据异构方案&#xff0c;把数据库中的值全部放到缓存热点缓存策略&#xff1a;通过分析调用日志获取热点数据&#xff0c;放到…

PMP项目管理-[第十一章]风险管理

风险管理知识体系&#xff1a; 规划风险管理&#xff1a; 识别风险&#xff1a; 实施定性风险分析&#xff1a; 实施定量风险分析&#xff1a; 监督风险&#xff1a; 11.1 风险 定义&#xff1a;是一种不确定的事件或条件&#xff0c;一旦发生&#xff0c;就会对一个或多个项目…

Elasticsearch(二)

Clasticsearch&#xff08;二&#xff09; DSL查询语法 文档 文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html 常见查询类型包括&#xff1a; 查询所有&#xff1a;查询出所有数据&#xff0c;一般测试用。如&#xff1a…

eNSP模拟器下VRRP+MSTP实验配置

①&#xff1a;底层配置&#xff1a; vlan trunk 略 ②&#xff1a;MSTP配置&#xff1a; 所有交换机&#xff1a; stp region-configuration region-name aa revision-level 1 instance 1 vlan 2 to 3 instance 2 vlan 4 to 5 active region-configuration 核心1&…

Java笔记_21(网络编程)

Java笔记_21 一、网路编程1.1、初始网络编程1.2、网络编程三要素1.3、IP1.4、端口号1.5、协议1.6、UDP协议 一、网路编程 1.1、初始网络编程 什么是网络编程 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行的数据传输。 应用场景:即时通信、网游对战…

(一)SAS初识

1、SAS常用工作窗口 “结果”&#xff08;Result&#xff09;窗口——管理SAS程序的输出结果&#xff1b; “日志”&#xff08;Log&#xff09;窗口——记录程序的运行情况&#xff1b; “SAS资源管理器”&#xff08;Explore&#xff09;窗口&#xff1b; “输出”&#xff0…

洛谷P1217-回文质数 Prime Palindromes

洛谷P1217-回文质数 Prime Palindromes 这个题目我做出来了但是超时了&#xff0c;时间复杂度有点高&#xff0c;主要是因为我用了大量的循环&#xff0c; 所以我这个是比较暴力的解法&#xff0c;下面我分析我的暴力代码 首先是判断回文数的函数 第一步将标识传入参数是不是…

[数据集][目标检测]篮球数据集VOC格式7398张

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;7398 标注数量(xml文件个数)&#xff1a;7398 标注类别数&#xff1a;1 标注类别名称:["basketball"]…

详解MNIST数据集下载、解析及显示的Python实现

Content MNIST数据集基本介绍下载MNIST数据集到本地解析MNIST数据集显示MNIST数据集中训练集的前9张图片和标签 随着图像处理、计算机视觉、机器学习&#xff0c;甚至深度学习的蓬勃发展&#xff0c;一个良好的数据集作为学习和测试相关算法非常重要。MNIST数据集对于想要学习和…

PMP 高项 07-项目质量管理

项目质量管理 概念 质量的基本概念 克劳斯比&#xff1a;符合要求 戴明&#xff1a;低成本条件下可预测的一致性和可靠度&#xff0c;适应市场需要 朱兰&#xff1a;适用性&#xff0c;满足客户需要 国际标准化组织&#xff1a;质量是反映实体&#xff08;产品、过程或活动等…

中间件容器化部署实现方案的前期调研

中间件容器化部署是为了实现GitOps模式的持续交付,实现部署即代码。痛点在于大多数中间件都是有状态的,本篇介绍如何实现有状态中间件的容器化部署。 常见中间件要实现容器化部署,需要解决以下问题: 对于网关类中间件,作为流量入口,虽然是无状态类型的中间件,但由于需要…

flask实现S3 Web客户端下载文件

import io from minio import Minio from minio.error import S3Error from flask import Flask, jsonify, render_template, request, send_file# 实例化 Flask 应用 app Flask(__name__)# 配置 MinIO 客户端 minio_client Minio("192.168.2.110:58894",access_ke…

Vue CLI 初始化脚手架

3.1. 初始化脚手架 3.1.1. 说明 Vue脚手架是Vue官方提供的标准化开发工具&#xff08;开发平台&#xff09;最新的版本是 4.x文档 Vue CLI 3.1.2. 具体步骤 如果下载缓慢请配置npm淘宝镜像npm config set registry http://registry.npm.taobao.org全局安装 vue/cli npm ins…

Python BP算法模板

BP算法模板 神经网络结构 三大基本结构 权重(轴突、树突) 权重的矩阵表示 数值(胞体) 数值处理方式 sigmoid 函数 def __sigmoid(self,x):return 1 / (1 np.exp(-x))sigmoid 的导函数 def __sigmoid_prime(self,x):return x * (1 - x)sigmoid 函数图像 其目的是将数值限制…

Java多线程synchronized Lock volatile,看完这一篇就够了

线程安全问题 一、对线程安全的理解&#xff08;实际上是内存安全&#xff09;二、线程同步的实现方法synchronized实现同步Lock实现同步volatile实现同步JUC的Callable实现同步 三、守护线程四、ThreadLocal原理和使用场景五、Thread类的常用方法&#xff0c;以及线程的状态六…

Linux下使用Mysql 第二天

目录 Mysql数据库API库 编写hello应用链接函数库 MySQL API常用函数 总体印象 初始化 Makefile 管理 连接数据库关闭连接 读取数据 查询表数据 获取结果集 解析结果集 释放结果集 获取列数 获取表头 实例程序 MySQL tools实现 思路分析 程序实现 中文问题 …

MS iCraft Z790ITX WIFI 电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板MS iCraft Z790ITX WIFI 处理器Intel Core i5-13400已驱动 内存Asgard DDR5 6400CL32 16GBx2 RGB已驱动 硬盘西数 WDS250G3X0C-00SJG0 ( SN750) …

如何设计API返回码(错误码)?

一、前言 客户端请求 API&#xff0c;通常需要通过返回码来判断 API 返回的结果是否符合预期&#xff0c;以及该如何处理返回的内容等 相信很多同学都吃过返回码定义混乱的亏&#xff0c;有的 API 用返回码是 int 类型&#xff0c;有的是 string 类型&#xff0c;有的用 0 表…