C++并发编程学习(四)——死锁及其预防
文章目录一、死锁介绍产生死锁的四个条件二、死锁防治方法方法1统一加锁顺序2.超时机制3.按层级加锁4.无锁编程一、死锁介绍死锁是指两个或多个进程或线程在执行过程中因争夺资源而造成的一种互相等待的现象导致所有涉及的进程都无法继续执行下去。比如有两个线程都需要同时锁住两个互斥才可以进行某项操作但它们分别都只锁住了一个互斥都等着再给另一个互斥加锁。于是双方毫无进展因为它们同在苦苦等待对方解锁互斥。一个经典的比喻哲学家就餐问题5 位哲学家围坐圆桌每人左右各有一根筷子吃饭需要同时拿起左右两根筷子如果每个人都先拿左边的筷子再等右边的就会全部卡住无人能吃饭引发死锁。产生死锁的四个条件必须同时满足以下四点才会发生死锁条件说明是否可破坏1. 互斥条件Mutual Exclusion资源一次只能被一个进程使用如打印机、mutex❌ 通常不可破坏资源本质决定2. 占有并等待Hold and Wait进程已持有至少一个资源同时等待其他被占用的资源✅ 可破坏3. 非抢占条件No Preemption已分配的资源不能被强制收回只能由持有者主动释放✅ 可破坏4. 循环等待Circular Wait存在一个进程等待环P₁→P₂→…→Pₙ→P₁✅ 可破坏c代码示例#includethread#includemutexstd::mutex mtx1,mtx2;voidthread1(){std::lock_guardstd::mutexlock1(mtx1);// 先锁 mtx1std::this_thread::sleep_for(std::chrono::milliseconds(10));std::lock_guardstd::mutexlock2(mtx2);// 再锁 mtx2}voidthread2(){std::lock_guardstd::mutexlock2(mtx2);// 先锁 mtx2std::this_thread::sleep_for(std::chrono::milliseconds(10));std::lock_guardstd::mutexlock1(mtx1);// 再锁 mtx1}intmain(){std::threadt1(thread1);std::threadt2(thread2);t1.join();t2.join();// 程序可能永远卡住}再比如假设有两个账户 A 和 B两个线程同时进行转账线程1从 A 转账到 B线程2从 B 转账到 A每个账户有一个自己的 mutex 保护余额。如果各自先锁“源账户”再锁“目标账户”就可能死锁// 危险代码可能导致死锁classAccount{public:intbalance;mutablestd::mutex m;Account(intb):balance(b){}};voidtransfer(Accountfrom,Accountto,intamount){std::lock_guardstd::mutexlock1(from.m);// 先锁 fromstd::this_thread::sleep_for(std::chrono::milliseconds(10));// 模拟延迟std::lock_guardstd::mutexlock2(to.m);// 再锁 tofrom.balance-amount;to.balanceamount;}二、死锁防治方法方法1统一加锁顺序上述转账例子使用std::lock()std::adopt_lock来原子地锁定多个互斥量从而彻底避免死锁#includeiostream#includethread#includevector#includemutexclassAccount{public:mutablestd::mutex m;// 每个账户一个 mutexintbalance;Account(intinitial_balance):balance(initial_balance){}};voidtransfer(Accountfrom,Accountto,intamount){// 关键使用 std::lock 原子地锁定多个 mutexstd::lock(from.m,to.m);// 无死锁风险// 使用 adopt_lock 告诉 lock_guard锁已经 acquiredstd::lock_guardstd::mutexlock_from(from.m,std::adopt_lock);std::lock_guardstd::mutexlock_to(to.m,std::adopt_lock);// 执行转账临界区from.balance-amount;to.balanceamount;// lock_guard 析构时自动 unlock顺序无关}intmain(){AccountA(1000),B(1000),C(1000);// 启动多个并发转账线程std::vectorstd::threadthreads;// A ↔ B 转账threads.emplace_back([](){for(inti0;i500;i){transfer(A,B,1);transfer(B,A,1);}});// B ↔ C 转账threads.emplace_back([](){for(inti0;i500;i){transfer(B,C,1);transfer(C,B,1);}});// A ↔ C 转账threads.emplace_back([](){for(inti0;i500;i){transfer(A,C,1);transfer(C,A,1);}});// 等待所有线程完成for(autot:threads){t.join();}// 验证总金额守恒应为 3000inttotalA.balanceB.balanceC.balance;std::coutA: A.balance\n;std::coutB: B.balance\n;std::coutC: C.balance\n;std::coutTotal: total (should be 3000)\n;return0;}2.超时机制std::timed_mutex mtx;if(mtx.try_lock_for(std::chrono::seconds(1))){// 成功获取锁mtx.unlock();}else{// 超时放弃或重试}3.按层级加锁把应用程序分层并且明确每个互斥位于哪个层级。若某线程已对低层级互斥加锁则不准它再对高层级互斥加锁。具体做法是将层级的编号赋予对应层级应用程序上的互斥并记录各线程分别锁定了哪些互斥:#includeiostream#includethread#includemutex//层级锁classhierarchical_mutex{public:explicithierarchical_mutex(unsignedlongvalue):_hierarchy_value(value),_previous_hierarchy_value(0){}hierarchical_mutex(consthierarchical_mutex)delete;hierarchical_mutexoperator(consthierarchical_mutex)delete;voidlock(){check_for_hierarchy_violation();_internal_mutex.lock();update_hierarchy_value();}voidunlock(){if(_this_thread_hierarchy_value!_hierarchy_value){throwstd::logic_error(mutex hierarchy violated);}_this_thread_hierarchy_value_previous_hierarchy_value;_internal_mutex.unlock();}booltry_lock(){check_for_hierarchy_violation();if(!_internal_mutex.try_lock()){returnfalse;}update_hierarchy_value();returntrue;}private:std::mutex _internal_mutex;//当前层级值unsignedlongconst_hierarchy_value;//上一次层级值unsignedlong_previous_hierarchy_value;//本线程记录的层级值staticthread_localunsignedlong_this_thread_hierarchy_value;voidcheck_for_hierarchy_violation(){if(_this_thread_hierarchy_value_hierarchy_value){throwstd::logic_error(mutex hierarchy violated);}}voidupdate_hierarchy_value(){_previous_hierarchy_value_this_thread_hierarchy_value;_this_thread_hierarchy_value_hierarchy_value;}};thread_localunsignedlonghierarchical_mutex::_this_thread_hierarchy_value(ULONG_MAX);voidtest_hierarchy_lock(){hierarchical_mutexhmtx1(1000);hierarchical_mutexhmtx2(500);std::threadt1([hmtx1,hmtx2](){hmtx1.lock();hmtx2.lock();hmtx2.unlock();hmtx1.unlock();});std::threadt2([hmtx1,hmtx2](){hmtx2.lock();hmtx1.lock();hmtx1.unlock();hmtx2.unlock();});t1.join();t2.join();}层级锁能保证我们每个线程加锁时一定是先加权重高的锁。并且释放时也保证了顺序。主要原理就是将当前锁的权重保存在线程变量中这样该线程再次加锁时判断线程变量的权重和锁的权重是否大于如果满足条件则继续加锁4.无锁编程使用原子操作std::atomic、CAS 等高性能但复杂适用于特定场景

相关新闻

DeepSeek-OCR-2与QT集成:跨平台文档处理应用开发

DeepSeek-OCR-2与QT集成:跨平台文档处理应用开发

DeepSeek-OCR-2与QT集成:跨平台文档处理应用开发 1. 为什么需要在QT中集成DeepSeek-OCR-2 日常工作中,我们经常遇到这样的场景:扫描的合同、PDF报告、手写笔记需要快速转换成可编辑的文本。传统OCR工具要么功能单一,要么部署复杂…

2026/5/17 4:25:16 阅读更多 →
LingBot-Depth模型解析:掩码深度建模原理简介

LingBot-Depth模型解析:掩码深度建模原理简介

LingBot-Depth模型解析:掩码深度建模原理简介 想不想让机器像人一样“看懂”三维世界?当我们看到一张照片,大脑能瞬间判断出物体的远近、形状和空间关系。但对计算机来说,这曾经是个巨大的挑战。传统的深度感知技术要么依赖昂贵的…

2026/5/17 4:25:13 阅读更多 →
Qwen3-ASR-1.7B与Linux命令结合实现自动化语音日志分析

Qwen3-ASR-1.7B与Linux命令结合实现自动化语音日志分析

Qwen3-ASR-1.7B与Linux命令结合实现自动化语音日志分析 1. 为什么服务器运维需要语音日志分析 凌晨三点,服务器告警邮件又来了。你揉着发酸的眼睛点开日志文件,密密麻麻的文本在屏幕上滚动——时间戳、进程ID、错误代码、堆栈跟踪……每一条都像在考验…

2026/7/4 4:38:01 阅读更多 →

最新新闻

Unity编辑器工具:高效处理3D模型的实用技巧

Unity编辑器工具:高效处理3D模型的实用技巧

1. Unity编辑器工具概述:模型处理的核心利器在Unity开发流程中,Editor工具链是提升工作效率的关键组件。针对3D模型处理这一高频需求,Unity提供了一系列原生和可扩展的编辑器功能,能够覆盖从资源导入到场景配置的全流程。不同于常…

2026/7/4 19:05:27 阅读更多 →
Mirror网络库插件优化与实战应用指南

Mirror网络库插件优化与实战应用指南

1. Mirror网络库插件深度解析Mirror作为Unity环境下广受欢迎的高性能网络库,其插件系统在实际项目开发中扮演着关键角色。这次我们将深入探讨第6代插件的核心特性与实战应用技巧,这些经验来自三个不同规模项目的实际验证。1.1 插件架构设计理念Mirror插件…

2026/7/4 19:05:27 阅读更多 →
数据中台架构设计与治理实战指南

数据中台架构设计与治理实战指南

1. 数据中台生态系统的核心价值三年前我接手某零售集团数据治理项目时,第一次深刻体会到数据孤岛的破坏力——市场部用T3的销售数据做促销决策,而仓储系统显示的是实时库存,这种数据割裂直接导致了一次千万级的营销事故。这正是数据中台要解决…

2026/7/4 19:03:27 阅读更多 →
claudecode如何放权?自动执行命令不再询问

claudecode如何放权?自动执行命令不再询问

0.shift tab开启自动模式1. 打开设置文件:在项目根目录或全局目录下找到 .claude/settings.json。2. 添加通配符白名单:修改 permissions 字段,加入 "Bash(*)"。完整配置如下:json{"permissions": {"all…

2026/7/4 19:03:27 阅读更多 →
LeetCode:买卖股票的最佳时机(1-3) - Python

LeetCode:买卖股票的最佳时机(1-3) - Python

121. Best Time to Buy and Sell Stock(买卖股票的最佳时机) 问题描述: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计…

2026/7/4 18:55:26 阅读更多 →
Git-Crypt与GitPod结合:云端IDE安全开发工作流实践

Git-Crypt与GitPod结合:云端IDE安全开发工作流实践

1. 项目概述:当云端IDE遇上加密仓库作为一名常年和代码、密钥、配置文件打交道的开发者,我深知一个痛点:如何在享受云端开发环境(如Gitpod)带来的极致便利时,又能确保敏感信息(如API密钥、数据库…

2026/7/4 18:53:26 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻