当前位置: 首页 > news >正文

C++并发多线程--死锁问题及解决方法

1--死锁问题

        死锁问题:两个线程访问资源时加锁,但都需要对方的资源才能执行释放锁;

        代码实例:下面的代码中,当线程 1 使用 my_mutex1 上锁后,会继续使用 my_mutex2 进行上锁,若此时线程 2 已经使用 my_mutex2 上锁了,也准备继续使用 my_mytex1 上锁;这时就会出现死锁问题:线程 1 掌握 my_mutex1 的资源,需要使用 my_mutex2 的资源,而线程 2 掌握 my_mutex2 的资源,需要使用 my_mutex1 的资源;两个线程都掌握各自需要的资源,导致两个线程无法继续执行,产生了死锁;

        一个简单的解决方案:将两个线程的上锁顺序设计为相同;

#include <iostream>
#include <thread>
#include <list>
#include <mutex> // 引入互斥class myClass{
public:// 收集数据到消息队列void inMsgRecvQueue(){for(int i = 0; i < 100; i++){// 模拟收集消息std::cout << "Running inMsgRecvQueue(), insert one value: " << i << std::endl; my_mutex1.lock();my_mutex2.lock();msgRecvqueue.push_back(i); // 消息队列存储消息my_mutex2.unlock();my_mutex1.unlock();}}// 从消息队列取数据void outMsgRecvQueue(){for(int i = 0; i < 100; i++){if(!msgRecvqueue.empty()){my_mutex2.lock(); // 加锁my_mutex1.lock(); // 加锁// 取出数据int command = msgRecvqueue.front();msgRecvqueue.pop_front(); my_mutex1.unlock(); // 解锁my_mutex2.unlock(); // 解锁}else{std::cout << "Running outMsgRecvQueue(), " "the msgRecvqueue is empty" << std::endl;}}}
private:std::list<int> msgRecvqueue; // 消息队列std::mutex my_mutex1; // 创建互斥量 std::mutex my_mutex2; // 创建互斥量 
};int main(int argc, char *argv[]){myClass sample1;// 使用成员函数创建线程std::thread myInMsgObj(&myClass::inMsgRecvQueue, &sample1); // 收集数据线程std::thread myOutMsgObj(&myClass::outMsgRecvQueue, &sample1); // 取出数据线程myInMsgObj.join();myOutMsgObj.join();return 0;
}

2--std::lock( )函数模板

        std::lock() 可以锁住两个或两个以上的互斥量,可以避免因为互斥量上锁顺序不同而导致的死锁问题;

        std::lock() 一般用于处理多个互斥量,其要么将多个互斥量同时锁住,要么将多个互斥量解锁(当部分互斥量未上锁时,要么等待其余互斥量上锁才继续执行,要么释放已经锁住的互斥量);

        下面的实例代码使用 std::lock() 来解决上面的死锁问题;

#include <iostream>
#include <thread>
#include <list>
#include <mutex> // 引入互斥class myClass{
public:// 收集数据到消息队列void inMsgRecvQueue(){for(int i = 0; i < 100; i++){// 模拟收集消息std::cout << "Running inMsgRecvQueue(), insert one value: " << i << std::endl; std::lock(my_mutex1, my_mutex2);msgRecvqueue.push_back(i); // 消息队列存储消息my_mutex2.unlock();my_mutex1.unlock();}}// 从消息队列取数据void outMsgRecvQueue(){for(int i = 0; i < 100; i++){if(!msgRecvqueue.empty()){std::lock(my_mutex1, my_mutex2);// 取出数据int command = msgRecvqueue.front();msgRecvqueue.pop_front(); my_mutex1.unlock(); // 解锁my_mutex2.unlock(); // 解锁}else{std::cout << "Running outMsgRecvQueue(), " "the msgRecvqueue is empty" << std::endl;}}}
private:std::list<int> msgRecvqueue; // 消息队列std::mutex my_mutex1; // 创建互斥量 std::mutex my_mutex2; // 创建互斥量 
};int main(int argc, char *argv[]){myClass sample1;// 使用成员函数创建线程std::thread myInMsgObj(&myClass::inMsgRecvQueue, &sample1); // 收集数据线程std::thread myOutMsgObj(&myClass::outMsgRecvQueue, &sample1); // 取出数据线程myInMsgObj.join();myOutMsgObj.join();return 0;
}

3--std::lock_guard( )函数模板

        std::lock_guard( ) 可以替换 mutex.lock() 和 mutex.unlock(),在项目复杂的时候可以避免遗漏上锁和解锁的问题;

        std::lock_guard<std::mutex> 对象名(互斥量, std::adopt_lock); std::adopt_lock 的作用是表明互斥量在之前已经上锁了,无需额外对互斥量进行上锁操作,只需进行解锁操作即可;

#include <iostream>
#include <thread>
#include <list>
#include <mutex> // 引入互斥class myClass{
public:// 收集数据到消息队列void inMsgRecvQueue(){for(int i = 0; i < 100; i++){// 模拟收集消息std::cout << "Running inMsgRecvQueue(), insert one value: " << i << std::endl; std::lock(my_mutex1, my_mutex2);msgRecvqueue.push_back(i); // 消息队列存储消息std::lock_guard<std::mutex> guard1(my_mutex1, std::adopt_lock);std::lock_guard<std::mutex> guard2(my_mutex2, std::adopt_lock);}}// 从消息队列取数据void outMsgRecvQueue(){for(int i = 0; i < 100; i++){if(!msgRecvqueue.empty()){std::lock(my_mutex1, my_mutex2);// 取出数据int command = msgRecvqueue.front();msgRecvqueue.pop_front(); std::lock_guard<std::mutex> guard1(my_mutex1, std::adopt_lock);std::lock_guard<std::mutex> guard2(my_mutex2, std::adopt_lock);}else{std::cout << "Running outMsgRecvQueue(), " "the msgRecvqueue is empty" << std::endl;}}}
private:std::list<int> msgRecvqueue; // 消息队列std::mutex my_mutex1; // 创建互斥量 std::mutex my_mutex2; // 创建互斥量 
};int main(int argc, char *argv[]){myClass sample1;// 使用成员函数创建线程std::thread myInMsgObj(&myClass::inMsgRecvQueue, &sample1); // 收集数据线程std::thread myOutMsgObj(&myClass::outMsgRecvQueue, &sample1); // 取出数据线程myInMsgObj.join();myOutMsgObj.join();return 0;
}

相关文章:

C++并发多线程--死锁问题及解决方法

1--死锁问题 死锁问题&#xff1a;两个线程访问资源时加锁&#xff0c;但都需要对方的资源才能执行释放锁&#xff1b; 代码实例&#xff1a;下面的代码中&#xff0c;当线程 1 使用 my_mutex1 上锁后&#xff0c;会继续使用 my_mutex2 进行上锁&#xff0c;若此时线程 2 已经使…...

【Spring】纯注解开发

1、简介 在Spring3.0升级了纯注解开发模式&#xff0c;使用Java类来代替配置文件&#xff0c;开启了Spring快速开发赛道。 2、定义bean Component Service Controller Repository 3、纯注解开发 使用Configuration声明一个配置类&#xff0c;使用ComponentScan来扫描作为bea…...

【算法心得】正确估计dfs时间复杂度;剪枝优化不怕重构

https://leetcode.cn/problems/verbal-arithmetic-puzzle/ 这题看到题&#xff0c;“表达式中使用的不同字符数最大为 10”&#xff0c;就觉得dfs就完事了&#xff0c;最多不过10!&#xff0c;10!才1e6&#xff0c;1e7这样。如果字符再少点&#xff0c;6! 7! 8!的&#xff0c;…...

通过网关访问微服务,一次正常,一次不正常 (nacos配置的永久实例却未启动导致)

微服务直接访问没问题&#xff0c;通过网关访问&#xff0c;就一次正常访问&#xff0c;一次401错误&#xff0c;交替正常和出错 负载均衡试了 路由配置检查了 最后发现nacos下竟然有2个order服务实例&#xff0c;我明明只开启了一个呀 原来之前的8080端口微服务还残留&…...

div输入框的文字超过指定行数用省略号表示css

实现效果&#xff1a;超过四行用省略号表示 实现方法&#xff1a; .text{overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 4; // 自定义行数-webkit-box-orient: vertical; }...

STM32 F103C8T6学习笔记5:定时器输出不同占空比PWM驱动舵机旋转角度

现在学习使用STM32 F103C8T6的定时器PWM模式&#xff0c;使用PWM驱动舵机转动不同角度&#xff0c;文章提供源码&#xff0c;测试工程&#xff0c;测试动态效果图。 目录 基础原理&#xff1a; 实验目标&#xff1a; 测试视频结果&#xff1a; 测试工程下载&#xff1a; 基…...

液体神经网络:LNN是个啥概念?

一、说明 在在人工智能领域&#xff0c;神经网络已被证明是解决复杂问题的非常强大的工具。多年来&#xff0c;研究人员不断寻求创新方法来提高其性能并扩展其能力。其中一种方法是液体神经网络&#xff08;LNN&#xff09;的概念&#xff0c;这是一个利用动态计算功能的迷人框…...

开源数据库Mysql_DBA运维实战 (DCL/日志)

SQL&#xff08;Structured Query Language 即结构化查询语言&#xff09; a.DDL语句 数据库定义语言&#xff1a; 数据库&#xff0c;表&#xff0c;视图&#xff0c;索引&#xff0c;存储过程&#xff0c;函数&#xff0c;创建删除ALTER(CREATE DROP ALTER) b.DML语句 数…...

神经网络基础-神经网络补充概念-03-逻辑回归损失函数

概念 逻辑回归使用的损失函数通常是"对数损失"&#xff08;也称为"交叉熵损失"&#xff09;或"逻辑损失"。这些损失函数在训练过程中用于衡量模型预测与实际标签之间的差异&#xff0c;从而帮助模型逐步调整权重参数&#xff0c;以更好地拟合数…...

基于深度信念神经网络的矿石产量预测,基于DBN的矿石产量预测,DBN的详细原理

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) DBN的矿石产量预测 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算法,本文将DBN算法进行矿石产量预测 DB…...

JavaWeb-Filter过滤器

目录 Filter过滤器 1. Filter的生命周期 2.Filter的配置 3.拦截路径 4.拦截具体的使用 5.拦截方式配置&#xff08;资源被访问方式&#xff09; 6.FilterChain拦截链 Filter过滤器 filter是过滤器&#xff0c;相比于Servlet的发送请求&#xff0c;filter是用于拦截请求。…...

python如何实现1ms内触发两个接口请求

在Python中&#xff0c;可以通过多线程或者协程来实现1ms内触发两个接口请求。以下是两种方法的示例代码&#xff1a; 1.多线程实现&#xff1a; import threading import requestsdef send_request(url):response requests.get(url)print(response.text)# 创建两个线程&…...

深入解析路由与网络:网络的脉络

目录 路由 广域网 公网 外网 局域网 内网 以太网 Wi-Fi CDN IPv4和IPv6 IP地址分类 无类别域间路由&#xff08;CIDR&#xff09; 路由 路由是指在计算机网络中&#xff0c;将数据包从源地址传递到目标地址的过程。在一个复杂的网络中&#xff0c;数据包需要经过多…...

spring.HttpMessageNotReadableException: JSON parse error

实体类如下&#xff1a; Value public class Search{//搜索内容String value;//是否模糊搜索boolean fuzzy true; //其实这样写并不是“默认”模糊搜索&#xff0c;而是“一定是”模糊搜索 }spring.HttpMessageNotReadableException: JSON parse error: Cannot construct ins…...

安全中间件的设计思路和简单实践

rasp 的侵入式特性和拦截特性导致开发和运维普通不太愿意配合&#xff0c;当生产环境出现问题时往往第一时间先把责任推给 rasp&#xff0c;逐渐的安全部门普遍只能把 rasp 设置为告警模式&#xff0c;而且越是大的集群拦截开的就越少&#xff0c;所以字节的 elkeid 和某外卖大…...

试卷扫描成电子版方法分享,这个方法不要错过

很多时候&#xff0c;为了方便传输我们需要将试卷扫描成电子版进行存档&#xff0c;以备不时之需。很多小伙伴如果遇到试卷需要扫描转成电子版可能就不知道该如何操作了&#xff0c;其实试卷扫描是一项非常重要的工作&#xff0c;因此需要注意一些方法和细节。以下是试卷扫描成…...

【PostgreSQL的CLOG解析】

同样还是这张图&#xff0c;之前发过shared_buffer和os cache、wal buffer和work mem的文章&#xff0c;今天的主题是图中的clog&#xff0c;即 commit log&#xff0c;PostgreSQL10之前放在数据库目录的pg_clog下面。PostgreSQL10之后修更名为xact,数据目录变更为pg_xact下面&…...

腾讯云国际站代充-阿里云ECS怎么一键迁移到腾讯云cvm?

今天主要来介绍一下如何通过阿里云国际ECS控制台一键迁移至腾讯云国际CVM。腾讯云国际站云服务器CVM提供全面广泛的服务内容。无-需-绑-定PayPal&#xff0c;代-充-值腾讯云国际站、阿里云国际站、AWS亚马逊云、GCP谷歌云&#xff0c;官方授权经销商&#xff01;靠谱&#xff0…...

东方晶源亮相第十一届半导体设备年会,共话发展“芯”机遇

8月11日&#xff0c;以“协力同芯抢机遇&#xff0c;集成创新造设备”为主题的第十一届&#xff08;2023年&#xff09;中国电子专用设备工业协会半导体设备年会暨产业链合作论坛&#xff08;CSEAC&#xff09;在无锡太湖国际博览中心圆满闭幕。为期3天的CSEAC&#xff0c;通过…...

git修改历史commit信息

修改历史提交 commit 的信息 操作步骤&#xff1a; git rebase -i 列出 commit 列表找到需要修改的 commit 记录&#xff0c;把 pick 修改为 edit 或 e&#xff0c;:wq 保存退出修改 commit 的具体信息git commit --amend&#xff0c;保存并继续下一条git 4. 4. rebase --cont…...

【源-荷-储协同互动】考虑源-荷-储协同互动的主动配电网优化调度研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f447; 关注我领取海量matlab电子书和数学建模资料&#x1f34a;个人信条&#xff1a;格物致知,完整Matl…...

2026年全场景适配最值得关注的五大能源管理系统

各位读者&#xff0c;大家好&#xff01;在全球能源结构加速转型的当下&#xff0c;能源管理系统的发展至关重要。今天我要为大家介绍2026年全场景适配最值得关注的五大能源管理系统。这些系统对于企业提升能源管理的精细化、智能化水平&#xff0c;增强核心竞争力有着重要意义…...

DOM DocumentImpl:深入解析文档对象模型的核心实现

DOM DocumentImpl:深入解析文档对象模型的核心实现 引言 在Web开发领域,DOM(文档对象模型)是前端开发的基础,它允许开发者通过JavaScript操作HTML文档。DOM DocumentImpl是DOM的核心实现之一,它提供了丰富的API来操作文档结构。本文将深入解析DOM DocumentImpl,帮助开…...

别再硬扛内存了:用Gensim的Word2Vec分批次处理超大语料库(附Python代码)

高效处理海量文本&#xff1a;Gensim Word2Vec分批次训练实战指南 当面对数十GB的文本数据时&#xff0c;传统的一次性加载方法往往会让内存不堪重负。本文将深入探讨如何利用Gensim库的Word2Vec实现分批次训练&#xff0c;突破内存限制&#xff0c;同时保持模型质量。 1. 大…...

银行家算法实战:用Python模拟死锁避免过程(附完整代码)

银行家算法实战&#xff1a;用Python模拟死锁避免过程&#xff08;附完整代码&#xff09; 在操作系统的资源管理领域&#xff0c;死锁问题就像程序员的噩梦——四个进程围坐在圆桌前&#xff0c;每个都紧握着别人需要的资源&#xff0c;却固执地不肯松手。这种僵局不仅会导致…...

CANoe诊断实战:从Console到Fault Memory的故障排查全流程

1. 当车辆故障灯突然亮起时&#xff0c;工程师如何用CANoe快速定位问题 那天我正在测试车间调试一台新车型的ECU&#xff0c;仪表盘上那个刺眼的黄色故障灯突然亮了起来。作为从业多年的汽车电子工程师&#xff0c;我立刻意识到这可能是偶发性故障——最让人头疼的问题类型。不…...

海康云台 ISPAI 二次开发

最近做了个视频会议的项目&#xff0c;硬件用的海康球机DS-2DC4A212IW-DE/C&#xff0c;甲方要求在会议内封装一个云台可以进行拖拽 控制摄像头方向以及焦距的功能&#xff0c;官方给的SDK还不能直接复用&#xff0c;只能手搓了&#xff0c;下面是代码可直接复用&#xff0c;需…...

4月3日打卡

20:20开始&#xff0c;学习90分钟...

Lumerical入门指南:从网格设置到材料库管理的实用技巧

1. 网格设置&#xff1a;从基础操作到高级技巧 第一次打开Lumerical时&#xff0c;网格设置可能是最让人困惑的部分。记得我刚接触这个软件时&#xff0c;经常因为网格设置不当导致仿真结果异常。网格就像建筑的地基&#xff0c;设置不当会导致整个仿真结构不稳。 在Lumerical中…...

从隔离菜谱到通用烹饪指南:Cook用户体验设计的完整演进之路

从隔离菜谱到通用烹饪指南&#xff1a;Cook用户体验设计的完整演进之路 【免费下载链接】cook &#x1f372; 好的&#xff0c;今天我们来做菜&#xff01;OK, Lets Cook! 项目地址: https://gitcode.com/gh_mirrors/co/cook 在数字化时代&#xff0c;烹饪应用已成为厨房…...