C++多线程编程(第三章 利用栈特性自动释放锁RALL,锁管理器、控制器)

news2024/11/15 8:45:05

1、什么是RALL,手动代码实现

RALL(resource Acquisition Is Initialization )C++ 之父Bjarne Stroustrup 提出;
使用局部对象来管理资源的技术称为资源获取即初始化;它的生命周期是由操作系统来管理的,无需人工介入;资源的销毁容易忘记,造成死锁或者内存泄漏。

1.1、手动实现RALL管理mutex资源

RALL 编写代码方式,代码更简介,而且不会遗漏解锁

#include <thread>
#include <iostream>
#include <string>
#include <mutex>
#include <shared_mutex>

using namespace std;

//RALL
class XMutex
{
public:
	XMutex(mutex & mux):mux_(mux)//引用的时候赋值,在初始化的时候就记到成员变量中
	{//构造函数中加锁
		cout << "Lock" << endl;
		mux.lock();
	}

	~XMutex()
	{
		cout << "UnLock" << endl;
		mux_.unlock();
	}
private:
	mutex& mux_;//把初始化的锁存下来,引用

};

static mutex mux;
void TestMutex(int status )
{//业务逻辑
	XMutex lock(mux);
	if (status == 1)
	{
		cout << "=1" << endl;
		return;
	}
	else
	{
		cout << "!= 1" << endl;
		return;
	}
	return;
}

int main()
{
	TestMutex(1);
	TestMutex(2);
	return 0;

}

在这里插入图片描述

1.2、C++ 11 支持的RALL管理互斥资源lock_guard

C++ 11 实现严格基于作用域的互斥体所有权包装器;
adopt_lock C++11 类型为adopt_lock_t ,假设调用方已拥有互斥的所有权;
通过{}控制锁的临界区
在这里插入图片描述
举例了三种情形

#include <thread>
#include <iostream>
#include <string>
#include <mutex>
#include <shared_mutex>

using namespace std;


static mutex gmutex;
void TestLockGuard(int i)
{//错误用法示例:这样写会被第一个线程占用,不能出来
	lock_guard<mutex> lock(gmutex);
	for (;;)
	{
		cout << "In " << i << endl;
		this_thread::sleep_for(500ms);
	}

}

void TestLockGuard_Demo2(int i)
{//正确用法,用大括号来释放锁
	{
		lock_guard<mutex> lock(gmutex);
		cout << "Begin thread " << i << endl;
	}
	for (;;)
	{
		{
			lock_guard<mutex> lock(gmutex);
			cout << "In " << i << endl;
			this_thread::sleep_for(200ms);
		}
		this_thread::sleep_for(1ms);
	}

}

void TestLockGuard_Demo3(int i)
{//举例开头拥有锁的初始化情况

	gmutex.lock();
	{
		//开头已经用有锁
		//lock_guard<mutex>lock(gmutex);//这样写会报错,因为这个锁在外部已经锁住了,通过捕获异常可以进行分析;
		lock_guard<mutex>lock(gmutex,adopt_lock);//如果外部锁住了,这样写可以避免(调用了重载特性),程序可以正常运行
		//解锁
	}


	{
		lock_guard<mutex> lock(gmutex);
		cout << "Begin thread " << i << endl;
	}
	for (;;)
	{
		{
			lock_guard<mutex> lock(gmutex);
			cout << "In " << i << endl;
			this_thread::sleep_for(200ms);
		}
		this_thread::sleep_for(1ms);
	}

}


int main()
{
	//printf("Demo1:\n");
	//for (int i = 0; i < 3; i++)
	//{
	//	thread th(TestLockGuard,i+1);
	//	th.detach();
	//}
	//getchar();


	//printf("Demo2:\n");
	//for (int i = 0; i < 3; i++)
	//{
	//	thread th(TestLockGuard_Demo2, i + 1);
	//	th.detach();
	//}
	//getchar();


	printf("Demo3:\n");
	for (int i = 0; i < 3; i++)
	{
		thread th(TestLockGuard_Demo3, i + 1);
		th.detach();
	}


	getchar();
	return 0;

}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.3、unique_lock C++ 11

unique_lock C++ 11实现可移动的互斥体所有权包装器
支持临时释放锁unlock
支持adopt_lock(已经用有锁,不加锁,出栈区会释放)
支持defer_lock(延后拥有,不加锁,出栈区不释放)
支持try_to_lock尝试获得互斥的所有权而不阻塞,获取失败退出栈区不会释放,通过owns_lock函数判断

#include <thread>
#include <iostream>
#include <string>
#include <mutex>
#include <shared_mutex>

using namespace std;


int main()
{
	{
		static mutex mux;
		{
			//第一种常规特性,与lock_guard使用方法一样,但是不一样的是,执行过程中可以临时释放锁,再加锁
			unique_lock<mutex>lock(mux);//
			lock.unlock();//但是unique_lock支持中间临时释放锁
			lock.lock();//加锁
		}//出栈释放锁


		{
			//第二个特性:已经用有锁,不锁定,退出解锁
			mux.lock();
			unique_lock<mutex>lock(mux,adopt_lock);//针对已经用有锁
		
		}
		{
			//第三个特性,延后加锁,不拥有,退出不解锁
			unique_lock<mutex>lock(mux,defer_lock);//延时锁,在后面再进行上锁
			lock.lock();//主动上锁,退出栈区解锁

		}
		{
			//mux.lock();//如果被锁定,后面也不会阻塞,不用有所
			//第四种特性,尝试加锁,不阻塞,失败不拥有锁
			unique_lock<mutex> lock(mux, try_to_lock);
			if (lock.owns_lock())
			{
				cout << "owns_lock" << endl;
			}
			else
			{
				cout << "not owns_lock" << endl;
			}
		
		}
	
	}
	getchar();

	return 0;

}

1.4、shared_lock C++ 14

C++14才有的特性
实现可移动的共享互斥体所有权封装器
使用方法:

#include <thread>
#include <iostream>
#include <string>
#include <mutex>
#include <shared_mutex>

using namespace std;


int main()
{
	{
		//共享锁
		static shared_timed_mutex tmux;
		//读取锁,共享锁
		{
			//调用共享锁
			shared_lock<shared_timed_mutex>lock(tmux);
			cout << "Read data" << endl;

		}//退出栈区释放构造,释放共享锁

		{
			//写入锁,互斥锁
			unique_lock<shared_timed_mutex>lock(tmux);
			cout << "write data" << endl;


		}
	}


	getchar();

	return 0;

}

1.5、scoped_lock C++17

scoped_lock C++17 用于多个互斥体的免死锁RAII封装器,类似lock
设置方法:
在这里插入图片描述

//要用到C++17,需要在属性->C++ ->语言 ->C++语言标注-> C++17


#include <thread>
#include <iostream>
#include <string>
#include <mutex>
#include <shared_mutex>

using namespace std;

static mutex mux1;
static mutex mux2;

void TestScope1()
{//死锁的测试代码
	this_thread::sleep_for(100ms);//模拟死锁,停100ms
	cout << "TestScope1 Begin mux1 lock" << endl;
	mux1.lock();
	cout << "TestScope1 Begin mux2 lock" << endl;
	mux2.lock();//死锁
	cout <<"In :TestScope1" << endl;
	this_thread::sleep_for(1000ms);
	mux1.unlock();
	mux2.unlock();
}
void TestScope2()
{//这个代码不变
	cout << "TestScope2 Begin mux2 lock" << endl;
	mux2.lock();
	this_thread::sleep_for(100ms);//模拟死锁,停100ms

	cout << "TestScope2 Begin mux1 lock" << endl;
	mux1.lock();//死锁
	cout << "In :TestScope2" << endl;

	this_thread::sleep_for(1500ms);
	mux2.unlock();
	mux1.unlock();
}


void TestScope1_C11()//C++11的解决方案
{
	this_thread::sleep_for(100ms);//模拟死锁,停100ms
	//cout << "TestScope1 Begin mux1 lock" << endl;
	//mux1.lock();
	//cout << "TestScope1 Begin mux2 lock" << endl;
	//mux2.lock();//死锁
	lock(mux1,mux2);//C++11的解决方案,两个同时锁住才能进行下一步操作,有一个没有锁住,则不进行下一步操作
	cout << "In :TestScope1" << endl;
	this_thread::sleep_for(1000ms);
	mux1.unlock();
	mux2.unlock();
}


void TestScope1_C17()//C++17的解决方案
{
	this_thread::sleep_for(100ms);//模拟死锁,停100ms
	//cout << "TestScope1 Begin mux1 lock" << endl;
	//mux1.lock();
	//cout << "TestScope1 Begin mux2 lock" << endl;
	//mux2.lock();//死锁
	//lock(mux1, mux2);//C++11的解决方案,两个同时锁住才能进行下一步操作,有一个没有锁住,则不进行下一步操作
	scoped_lock lock(mux1,mux2);//C++17的解决方案,必须要把属性设置为C++17才行

	cout << "In :TestScope1" << endl;
	this_thread::sleep_for(1000ms);
	//mux1.unlock();//C++17这种方法改后,这里不需要手动释放,否则会报错
	//mux2.unlock();
}



int main()
{
	{
		//printf("Demo1:演示死锁:\n");
		演示死锁
		//{
		//	thread th(TestScope1);
		//	th.detach();
		//}

		//printf("Demo2:演示C++11解决死锁方案:\n");
		//{//C++ 11的解决方案
		//	thread th(TestScope1_C11);
		//	th.detach();
		//}

		printf("Demo3:演示C++17解决死锁方案:\n");
		{//C++ 17的解决方案
			thread th(TestScope1_C17);
			th.detach();
		}


		{//下面代码不注释,不动
			thread th(TestScope2);
			th.detach();
		}
		
	}

	getchar();

	return 0;

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Hive分区分桶

分区 分区概念 在逻辑上分区表与未分区表没有区别&#xff0c;在物理上分区表会将数据按照分区键的列值存储在表目录的子目录中&#xff0c;目录名“分区键键值”。其中需要注意的是分区键的值不一定要基于表的某一列&#xff08;字段&#xff09;&#xff0c;它可以指定任意…

ubuntu软件:录制视频和截图工具,压缩视频

1. 自带录制视频工具&#xff1b; 使用方式&#xff1a; 无需下载 开始录屏/结束录屏&#xff1a;Ctrl Alt Shift r 当看到 Ubuntu 桌面的右上方多了一个红色的小圆点&#xff0c;代表正在录制 注意&#xff1a; 录屏默认的时长30秒&#xff0c;超时会自动结束&#xff01…

Postman如何导出接口的几种方法

本文主要介绍了Postman如何导出接口的几种方法&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下 前言&#xff1a; 我的文章还是一贯的作风&#xff0c;简确用风格&#xff08;简单确实有用&#xff09;&am…

无涯教程-jQuery - serialize( )方法函数

serialize()方法将一组输入元素序列化为数据字符串。 serialize( ) - 语法 $.serialize( ) serialize( ) - 示例 假设无涯教程在serialize.php文件中具有以下PHP内容- <?php if( $_REQUEST["name"] ) {$name$_REQUEST[name];echo "Welcome ". $na…

JavaScript小结测试

题目 有两个体操队&#xff0c;海豚队和考拉队。他们互相竞争3次。平均得分最高的赢家将获得奖杯! 利用下面的测试数据&#xff0c;计算每队的平均得分 比较各队的平均分&#xff0c;以确定比赛的获胜者&#xff0c;并将其打印到控制台。不要忘了可能会出现平局&#xff0c;所…

ENVI提取NDVI与植被覆盖度估算

目标是通过ENVI计算植被覆盖度结合ArcGIS出图得到植被覆盖图。 一、植被覆盖度的定义: 植被覆盖度( FractionalVegetation Cover,FVC) 通常定义为植被( 包括叶、茎、枝) 在地面的垂直投影面积占统计区总面积的百分比,它量化了植被的茂密程度,反应了植被的生长态势,是刻画…

C语言结构体大小分析

一&#xff0c;基本类型 C语言自带的数据类型大小如下 数据类型大小&#xff08;字节&#xff09;char1short2int4long4或8float4double8long double16 二&#xff0c;自定义类型---struct C语言除了以上这些基本类型&#xff0c;还支持用户自己定义数据类型 类似于一下形…

Android Banner - ViewPager

现在来给viewpager实现的banenr加上自动轮播 自动轮播的原理&#xff0c;使用handler的延迟消息来实现。 自动轮播实现如下内容 开始轮播&停止轮播 可配置轮播时长、轮播方向 通过自定义属性来配置轮播时长&#xff0c;方向 感知生命周期&#xff0c;可见时开始轮播&…

【Ansible】Ansible自动化运维工具的应用与常用命令

ansible自动化运维工具 一、ansible 的概述1. ansible 的概念2. ansible 的特性 二、ansible 的部署与命令1. ansible 的部署1.1 服务器ip地址设置1.2 ansible 服务器部署 2. ansible 命令行模块2.1 command 模块2.2 shell 模块2.3 cron 模块2.4 user 模块2.5 group 模块2.6 co…

Spring Batch教程(三)示例:从mysql中读取数据写入文本和从多个文本中读取内容写入mysql

Spring batch 系列文章 Spring Batch教程&#xff08;一&#xff09; 简单的介绍以及通过springbatch将xml文件转成txt文件 Spring Batch教程&#xff08;二&#xff09;示例&#xff1a;将txt文件转成xml文件以及读取xml文件内容存储到数据库mysql Spring Batch教程&#xff…

在CSDN的几年,我的Python书籍,第三次重印了!

大家好&#xff0c;我是黄伟&#x1f92d; 我的书籍《快学Python&#xff1a;自动化办公轻松实战》第3次重印了&#xff0c;感谢大家的支持。 这本书干货多多&#xff0c;零基础教你Python自动化办公&#xff0c;让你工作效率提升10倍&#xff0c;提前1小时下班。 因此&#…

2018年全国硕士研究生入学统一考试管理类专业学位联考写作试题——解析版

2018年1月真题 四、写作&#xff1a;第56~57小题&#xff0c;共65分。其中论证有效性分析30 分&#xff0c;论说文35分。 56.论证有效性分析&#xff1a; 分析下述论证中存在的缺陷和漏洞&#xff0c;选择若干要点&#xff0c;写一篇600字左右的文章&#xff0c;对该论证的有…

「开源项目」现代化开源Linux服务器运维管理面板-1Panel

1Panel 基本介绍 1Panel 是新一代的 Linux 服务器运维管理面板 产品优势 快速建站&#xff1a;深度集成 Wordpress 和 Halo&#xff0c;域名绑定、SSL 证书配置等一键搞定&#xff1b; 高效管理&#xff1a;通过 Web 端轻松管理 Linux 服务器&#xff0c;包括应用管理、主机监控…

二分图算法(染色法 匈牙利算法)

目录 二分图算法总览二分图的概念1.二分图的定义2.二分图的特点3.二分图的应用 染色法&#xff08;判断二分图&#xff09;算法步骤算法运用染色法判定二分图 匈牙利算法&#xff08;计算二分图的最大匹配&#xff09;二分图的匹配算法步骤算法应用二分图的最大匹配 二分图算法…

Jmeter并发测试

基本步骤 1、新建线程组 测试计划右键——>添加——>线程&#xff08;用户&#xff09;——>线程组 2、 添加HTTP请求 线程组右键——>添加——>取样器——>HTTP请求 3、 添加HTTP信息头管理器 线程组右键——>添加——>配置元件——>HTTP信息头…

【观察】以超融合创新架构,加速企业应用现代化

我们知道&#xff0c;数字化转型的不断加速&#xff0c;核心就是应用的加速。在整个数字化体系中&#xff0c;软件应用是让一切发挥价值的落地路径。在应用发挥能力之前&#xff0c;企业需要进行大量软硬件准备以及应用开发工作&#xff1b;在应用开始发挥能力之&#xff0c;企…

牛客小白月赛75F题解

文章目录 [ 打牌](https://ac.nowcoder.com/acm/contest/60063/F)问题建模问题分析代码 打牌 问题建模 给出三个长度为3的字符串&#xff0c;每个字符串仅由’w’,‘i’,‘n’三种字符组成&#xff0c;以及回合数n&#xff0c;每一个回合每一个字符串选择一个字符向其下一个字…

【Android】底层逻辑深入了解(学习笔记)(未完)

step by step. 目录 init启动 Zygote进程&#xff1a; SystemServer处理过程 Binder&#xff1a; Launcher启动过程 Android系统启动流程 四大组件 Activity Service BroadcastReceiver广播 ContentProvider内容提供者&#xff08;进程内和进程间的数据共享&#xff…

Latex | 使用MATLAB生成.eps矢量图并导入Latex中的方法

一、问题描述 用Latex时写paper时&#xff0c;要导入MATLAB生成的图进去 二、解决思路 &#xff08;1&#xff09;在MATLAB生成图片的窗口中&#xff0c;导出.eps矢量图 &#xff08;2&#xff09;把图上传到overleaf的目录 &#xff08;3&#xff09;在文中添加相应代码 三…

深度学习100例 | 第31天-卷积神经网络(DenseNet)识别生活物品

&#x1f680; 我的环境&#xff1a; 语言环境&#xff1a;Python3.6.5编译器&#xff1a;jupyter notebook深度学习环境&#xff1a;TensorFlow2.4.1显卡&#xff08;GPU&#xff09;&#xff1a;NVIDIA GeForce RTX 3080数据&#xff1a;&#x1f4cc;【传送门】 &#x1f…