线程间互斥-mutex互斥锁和lock_guard

news2024/11/14 21:01:00

要点

  • 锁+双重判断的技法

  • 竟态条件:多线程程序执行的结果一致,不会随着CPU对线程不同的调用顺序

线程间安全实例——3个窗口同时卖票

线程不安全的代码如下

int ticketCount = 100; // 100张车票
// 模拟10个窗口同时卖票
void sellTicket(int index)
{
	while (ticketCount > 0)
	{
		//cout << "窗口:" << index << "卖出第:" << ticketCount << "张票" << endl;
		cout << ticketCount << endl; // 打印当前剩余票数
		ticketCount--;
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}
int main()
{
	list<std::thread> tlist;
	for (int i = 1; i <= 3; ++i)
	{
		tlist.push_back(std::thread(sellTicket, i));
	}

	for (std::thread& t : tlist)
	{
		t.join();
	}

	cout << "所有窗口卖票结束!" << endl;
	return	0;
}

输出的部分结果里有很多重复的数字,相当于同一张票被卖出多次,原因在于

ticketCount–; 是线程不安全的,理由如下

在这里插入图片描述

某一时刻ticketCount = 99,thread1此时调用ticketCount–,执行到sub eax时执行线程切换到另一个线程thread2中,此时ticketCount仍为99,执行完3条汇编后ticketCount = 98,此时再切换回thread1,继续执行完后面汇编,也使ticketCount = 98,这里就导致同时输出两次98;

解决方法

保证某一线程ticketCount–没做完,其他线程不允许做ticketCount–操作,可以使用加mutex互斥锁的方法:

void sellTicket(int index)
{
	mtx.lock();
	while (ticketCount > 0)
	{
		//cout << "窗口:" << index << "卖出第:" << ticketCount << "张票" << endl;
		cout << ticketCount << endl; // 打印当前剩余票数
		ticketCount--;
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
	mtx.unlock();
}

但是这样的加锁问题在于锁粒度太大,可以进一步缩小,采用锁+双重判断的方法:

void sellTicket(int index)
{
	while (ticketCount > 0)
	{
		mtx.lock();
		if (ticketCount > 0) // !!!
		{
			cout << "窗口:" << index << "卖出第:" << ticketCount << "张票" << endl;
			//cout << ticketCount << endl; // 打印当前剩余票数
			ticketCount--;
		}
		mtx.unlock();
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}

这里if (ticketCount > 0) 判断必须加,如果不加,当ticketCount = 1时,切换到其他线程卖完后ticketCount = 0 ,切换回原线程继续卖票就变成可以卖第0张票,不合法

lock_guard和unique_lock

lock_guard

lock_guard不能用在函数参数传递返回过程中,只能用在简单的临界区代码段互斥操作;

类似于scoped_str

lock_guard是对std::mutex的封装,拷贝构造和赋值函数被delete,它是RAII技术的实践,创建对象时就加锁,出作用域析构调用解锁,用lock_guard替换上面案例的mutex:

void sellTicket(int index)
{
	while (ticketCount > 0)
	{
		//mtx.lock();
		{
			lock_guard<std::mutex> lock(mtx); // 
			if (ticketCount > 0)
			{
				cout << "窗口:" << index << "卖出第:" << ticketCount << "张票" << endl;
				ticketCount--;
			}
		} 
		//mtx.unlock();
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}

unique_lock

unique_lock不仅可用在函数参数传递或返回过程中,还能用在函数调用中,如 和条件变量函数一起使用:

unique_lock<std::mutex> lck(mtx);

cv.wait(lck); // => #1.使线程进入等待状态 #2.lck.unlock可以把mtx给释放掉

unique_lock 也是对mutex的封装,它也可以像lock_guard一样使用,同时它支持手动调用lock unlock,会帮助检查是否忘记调用unlock,使用例子如下:

void sellTicket(int index)
{
	while (ticketCount > 0)
	{
		{
			unique_lock<std::mutex> lck(mtx);
			lck.lock();
			if (ticketCount > 0)
			{
				cout << "窗口:" << index << "卖出第:" << ticketCount << "张票" << endl;
				ticketCount--;
			}
			lck.unlock();
		} 
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}

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

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

相关文章

PostgreSQL11 | 索引

截止到上一篇《PostgreSQL11 | 查询数据》属于pgsql的基础部分就算是都总结完了&#xff0c;从这一篇&#xff08;第9章&#xff09;开始一直到本专栏最后一篇文章&#xff08;第14章&#xff09;都是进阶部分&#xff0c;sql量会减弱&#xff0c;抽象的概念会越来越多&#xf…

数字识别问题

文章目录 6.1 MNIST数据处理6.2.1 训练数据6.2.2 变量管理6.3.1 保存模型6.3.1 加载计算图6.3.1 加载模型6.3.2 导出元图 6.1 MNIST数据处理 在直接在第6章的目录下面创建文件 compat.v1.是tensorflow2.x的语法&#xff0c;全部删掉 删除compat.v1.后的代码 # -*- coding: …

【SCI一区】考虑P2G和碳捕集设备的热电联供综合能源系统优化调度模型(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

学术必备的21个论文网站,建议收藏!

1、综合型论文网站&#xff08;国内&#xff09; &#xff08;1&#xff09;知网 介绍&#xff1a;国内知名度最高的网站&#xff0c;拥有上亿篇各种论文期刊&#xff0c;包含中国学术文献、 外文文献、学位论文、报纸、会议、年鉴、工具书等各类资源统一检索、统一导 航、…

第四章 图像的形态学操作

文章目录 前言一、阈值控制二、腐蚀与膨胀1.腐蚀2.膨胀3.形态学操作 总结 前言 前面讲解了图像基础理论、图像的变换以及图像滤波等操作&#xff0c;本章&#xff0c;将会介绍图像的形态学操作。 图像的形态学指的是一组数学方法和工具&#xff0c;用于图像分析和处理。形态学…

(7)Qt---文件IO

目录 1. QFileDialog 文件选择对话框** 2. QFileInfo 文件信息类** 3. QFile 文件读写类*** 4. UI与耗时操作** 5. QThread 线程类 5.1 复现阻塞 5.2 新建并启动子线程 5.3 异步刷新 5.4 停止线程 1. QFileDialog 文件选择对话框** 操作系统会提供一个统一样式的文件选择对话框…

从本地到云端:豆瓣如何使用 JuiceFS 实现统一的数据存储

豆瓣成立于 2005 年&#xff0c;是中国最早的社交网站之一。在 2009 到 2019 的十年间&#xff0c;豆瓣数据平台经历了几轮变迁&#xff0c;形成了 DPark Mesos MooseFS 的架构。 由机房全面上云的过程中&#xff0c;原有这套架构并不能很好的利用云的特性&#xff0c;豆瓣需…

少林派问题汇总

少林派问题汇总&#xff1a; Q: A:缺少bmodel,没有指定bmodel的路径&#xff0c;测试图片不在同一文件路径下 复制过来就解决了 Q: docker容器下运行./install_lib.sh nntc会rm不到文件怎么回事? A&#xff1a;文件已经被删除 Q: 我将pytorch的模型用export工具转换成.torch…

聚焦丨酷雷曼荣列XRMA联盟成员单位

自“元宇宙”概念兴起之初&#xff0c;酷雷曼VR所属北京同创蓝天云科技有限公司就积极布局、探索和实践。2022年12月&#xff0c;酷雷曼VR成功加入虚拟现实与元宇宙产业联盟&#xff08;XRMA&#xff09;&#xff0c;正式被接纳为联盟成员单位&#xff0c;意味着酷雷曼公司将进…

详细版易学版TypeScript - 元组 枚举详解

一、元组(Tuple) 数组:合并了相同类型的对象 const myArr: Array<number> [1, 2, 3]; 元组(Tuple):合并了不同类型的对象 // 定义元组时就要确定好数据的类型&#xff0c;并一一对应 const tuple: [number, string] [12, "hi"]; // 添加内容时&#xff0c;不…

代码随想录算法训练营day35 | 860.柠檬水找零,406.根据身高重建队列,452. 用最少数量的箭引爆气球

代码随想录算法训练营day35 | 860.柠檬水找零&#xff0c;406.根据身高重建队列&#xff0c;452. 用最少数量的箭引爆气球 860.柠檬水找零406.根据身高重建队列452. 用最少数量的箭引爆气球 860.柠檬水找零 教程视频&#xff1a;https://www.bilibili.com/video/BV12x4y1j7DD/…

3.SpringBoot开发实用篇

SpringBoot开发实用篇 ​ 开发实用篇中因为牵扯到SpringBoot整合各种各样的技术&#xff0c;由于不是每个小伙伴对各种技术都有所掌握&#xff0c;所以在整合每一个技术之前&#xff0c;都会做一个快速的普及&#xff0c;这样的话内容整个开发实用篇所包含的内容就会比较多。各…

推荐系统综述

这里写目录标题 推荐系统架构1、传统推荐方式1.1 基于内容推荐&#xff08;Content-Based recommendation&#xff0c;CB&#xff09;1.2 协同过滤推荐&#xff08;Collaborative Filtering recommendation&#xff0c; CF&#xff09;1.2.0 UserCF举例&#xff1a;1. 2. 1 基于…

window-2016服务器;服务——活动目录

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️树高千尺&#xff0c;落叶归根人生不易&…

OpenCL编程指南-2.1HelloWorld

在windows下编写HelloWorld 按照前面文章搭建好OpenCL的环境https://blog.csdn.net/qq_36314864/article/details/130513584 main函数完成以下操作&#xff1a; 1&#xff09;在第一个可用平台上创建OpenCL上下文 2&#xff09;在第一个可用设备上创建命令队列 3&#xff09;…

第二期 | ICASSP 2023 论文预讲会

ICASSP 2023 论文预讲会是由CCF语音对话与听觉专委会、语音之家主办&#xff0c;旨在为学者们提供更多的交流机会&#xff0c;更方便、快捷地了解领域前沿。活动将邀请 ICASSP 2023 录用论文的作者进行报告交流。 ICASSP 2023 论文预讲会邀请到清华大学人机语音交互实验室&…

单细胞跨模态分析综述

单细胞技术的最新进展使跨模态和组织位置的细胞高通量分子分析成为可能。单细胞转录组数据现在可以通过染色质可及性、表面蛋白表达、适应性免疫受体库分析和空间信息进行补充。跨模态单细胞数据的可用性越来越高&#xff0c;推动出新的计算方法&#xff0c;以帮助科学家获得生…

图的遍历——深度优先搜索(DFS)与广度优先搜索(BFS)(附带C语言源码)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️数据结构与算法】 学习名言&#xff1a;天子重英豪&#xff0c;文章教儿曹。万般皆下品&#xff0c;惟有读书高——《神童诗劝学》 系列文章目录 第一章 ❤️ 学前知识 第二章 ❤️ 单向链表 第三章…

mysql数据迁移与同步常用解决方案总结

目录 一、前言 二、数据迁移场景 2.1 整库迁移 2.2 表数据迁移 2.3 mysql版本变更 2.4 mysql数据迁移至其他存储介质 2.5 自建数据到上云环境 2.6 mysql数据到其他国产数据库 三、数据库物理迁移实施方案 3.1 数据库物理迁移概述 3.1.1 物理迁移适用场景 3.1.2 物理…

杂记 2023.5.10

目录 韦伯和斯托亚科维奇是谁&#xff1f; 介绍一下kali FastDFS和Sentinel是什么&#xff1f; Inferno 找工作的影响因素 1. 背景&#xff1a; 2. 学习过程&#xff1a; 2.1 计算机基础&#xff1a; 2.2 语言&#xff1a; 2.3 数据库等&#xff1a; 2.4 JVM&#…