多线程之互斥锁与死锁:一个真实死锁bug让我排查了整整两天
上篇把线程创建与管理聊了。今天聊多线程里最让人头疼的问题——数据竞争和死锁。先讲个真实的bug故事。之前做一个多传感器融合的项目激光雷达和IMU的数据分别由两个线程读取融合之后发布。上线测试的时候程序跑着跑着就卡死了——不是崩溃是卡住不动了。没有任何错误日志就是所有线程都不干活了。排查了两天最后发现是死锁。问题出在哪两个线程各自持有两把锁但加锁顺序不一样// 线程A先锁lidar_mutex再锁fusion_mutex void lidarThread() { while (running_) { lock_guardmutex lock1(lidar_mutex_); auto scan latestScan_; lock_guardmutex lock2(fusion_mutex_); // 等fusion_mutex fusionData_.lidar scan; } } // 线程B先锁fusion_mutex再锁imu_mutex void imuThread() { while (running_) { lock_guardmutex lock1(imu_mutex_); auto imu latestImu_; lock_guardmutex lock2(fusion_mutex_); // 也等fusion_mutex fusionData_.imu imu; } }某个时刻线程A拿了lidar_mutex_等fusion_mutex_线程B拿了imu_mutex_也要等fusion_mutex_——等等这其实不是死锁只是竞争。真正的死锁是互相等对方手里的锁。让我还原一下当时的真实场景// 真正的死锁场景 void threadA() { mutex1_.lock(); // A拿了mutex1 // ... 做一些事 mutex2_.lock(); // A等mutex2 } void threadB() { mutex2_.lock(); // B拿了mutex2 // ... 做一些事 mutex1_.lock(); // B等mutex1 // 死锁A等B的mutex2B等A的mutex1 }mutex的基本用法C11提供了std::mutex来解决数据竞争。基本用法很简单mutex mtx; int sharedCounter 0; void increment() { mtx.lock(); sharedCounter; // 临界区同一时间只有一个线程能访问 mtx.unlock(); }但直接用lock/unlock很危险——如果临界区里抛了异常unlock不会被执行锁就永远不会释放。所以C推荐使用RAII方式的lock_guard或unique_lockvoid increment() { lock_guardmutex lock(mtx); // 构造时加锁 sharedCounter; // 析构时自动解锁即使抛异常也安全 }lock_guard是最简单的锁包装——构造加锁析构解锁没有别的选项。unique_lock更灵活支持延迟加锁、手动解锁、try_lockvoid flexibleLock() { unique_lockmutex lock(mtx, defer_lock); // 先不锁 // 做一些不需要锁的事 prepareData(); lock.lock(); // 现在才加锁 criticalSection(); lock.unlock(); // 可以手动解锁 // 非阻塞尝试 if (lock.try_lock()) { // 拿到锁了 } else { // 没拿到做别的事 } }死锁的四个必要条件死锁的发生需要同时满足四个条件互斥——资源同一时间只能被一个线程持有。锁天然是互斥的这个没法消除。持有并等待——线程持有一把锁的同时等待另一把锁。不可抢占——锁不能被强制从持有者手里夺走。循环等待——线程A等B持有的锁B等C持有的锁C又等A持有的锁。要防止死锁只要打破其中任意一个条件就行。最实用的做法是打破循环等待——让所有线程按相同的顺序加锁。// 解决方案统一加锁顺序 void threadA() { lock_guardmutex lock1(mutex1_); // 先锁1 lock_guardmutex lock2(mutex2_); // 再锁2 } void threadB() { lock_guardmutex lock1(mutex1_); // 同样的顺序 lock_guardmutex lock2(mutex2_); // 先锁1再锁2 }C17还提供了一个更方便的工具——std::lock可以同时锁多把锁而不死锁void transferMoney(Account from, Account to, double amount) { // std::lock同时锁两个mutex内部用try-and-back-off避免死锁 lock(from.mutex_, to.mutex_); lock_guardmutex lockFrom(from.mutex_, adopt_lock); lock_guardmutex lockTo(to.mutex_, adopt_lock); from.balance_ - amount; to.balance_ amount; }机器人开发中的典型数据竞争在机器人系统里数据竞争最常出现在传感器数据和共享状态上。class SensorFusion { mutex mtx_; Pose currentPose_; public: void updateFromImu(const ImuData data) { lock_guardmutex lock(mtx_); currentPose_ integrateImu(data); } void updateFromLidar(const LidarScan scan) { lock_guardmutex lock(mtx_); currentPose_ matchLidar(scan); } Pose getPose() { lock_guardmutex lock(mtx_); return currentPose_; } };这个设计是对的但要注意锁的粒度。如果临界区太大锁住了大量计算其他线程就得等着并行度下降。如果临界区太小只锁了一个赋值可能保护不够。经验法则是只锁住访问共享数据的那几行代码计算逻辑放在锁外面。面试中的关键考点mutex和spinlock有什么区别mutex拿不到锁时会阻塞线程让出CPUspinlock拿不到锁时会一直循环尝试忙等不让出CPU。mutex适合临界区较长的场景spinlock适合临界区极短几个指令的场景。recursive_mutex是什么允许同一个线程对同一把mutex多次加锁而不会死锁。但一般不推荐用——如果你发现需要recursive_mutex多半是设计有问题。怎么排查死锁Linux下可以用gdb attach到进程看每个线程的调用栈找出各自持有什么锁、在等什么锁。工具层面可以用ThreadSanitizerTSan编译时加-fsanitizethread就能检测潜在的数据竞争。给正在准备面试的你互斥锁和死锁是面试高频考点。基本的mutex用法必须熟练lock_guard和unique_lock的区别要能讲清楚。死锁的四个条件和预防方法也要能说出来。最重要的是写代码的时候要有锁的意识。拿到一把锁的时候脑子里就要想清楚——这把锁和其他锁有没有顺序冲突会不会和其他线程的加锁顺序形成环路养成这个好习惯能帮你避免绝大多数死锁问题在面试和实际项目开发中都非常有用。下篇聊条件变量——生产者消费者模型在传感器数据流中的实际应用。这是多线程协作的核心机制和重要基础。如果这篇文章对你有帮助欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。「机器人软件开发面试·从入门到精通」连载系列上一篇第54篇 多线程之线程创建与管理——机器人系统中为什么必须用多线程 下一篇预告第56篇 多线程之条件变量——生产者消费者模型在传感器数据中的应用有任何问题欢迎评论区留言我会尽量回复。

相关新闻

Tiva TM4C123BE6PM管脚功能详解与配置实战

Tiva TM4C123BE6PM管脚功能详解与配置实战

1. 项目概述与核心价值对于任何一位嵌入式硬件工程师或单片机开发者而言,拿到一颗新的微控制器(MCU)后,第一件要紧事就是“啃”数据手册里的管脚定义表。这看似枯燥的表格,却是连接芯片内部强大功能与外部现实世界的唯…

2026/7/23 9:11:37 阅读更多 →
多线程之线程创建与管理:面试官问“机器人系统为什么必须用多线程”

多线程之线程创建与管理:面试官问“机器人系统为什么必须用多线程”

从今天开始进入多线程板块。这块内容在C面试里分量很重——互斥锁、死锁、条件变量、原子操作、线程池,一连串的话题,每个都能聊一篇。先从最基础的开始:线程的创建与管理。为什么要用多线程?这个问题在机器人开发里答案特别明确&…

2026/7/23 7:15:17 阅读更多 →
2024年7月AI大模型技术报告:Gemini、Grok、GPT最新突破与编程模型格局

2024年7月AI大模型技术报告:Gemini、Grok、GPT最新突破与编程模型格局

最近在AI领域真是热闹非凡,各大厂商都在密集发布新模型和功能更新。如果你正在关注AI大模型的最新进展,特别是Gemini、Grok和GPT系列的最新动态,那么本文正好为你整理了一份完整的7月AI技术发展报告。本文将详细解析Gemini 3.5 Pro的发布预测…

2026/7/23 9:21:29 阅读更多 →

最新新闻

AI原生应用中的函数调用技术解析与实践

AI原生应用中的函数调用技术解析与实践

1. AI原生应用中的函数调用革命去年我在开发一个智能客服系统时,第一次真正体会到AI原生应用的威力。传统开发中,我们需要为每个业务场景编写大量if-else逻辑,而采用函数调用机制后,大模型能够自主判断何时调用哪些API&#xff0c…

2026/7/23 20:55:44 阅读更多 →
RAG技术选型:轻量与大场景的优化策略

RAG技术选型:轻量与大场景的优化策略

1. RAG技术选型的核心矛盾与解决思路最近半年在帮三家不同规模的企业落地RAG系统时,发现一个有趣的现象:初创团队总想用最轻量的方案解决所有问题,而中大型企业则倾向于堆砌复杂架构。结果往往是前者遇到性能瓶颈,后者浪费大量资源…

2026/7/23 20:55:44 阅读更多 →
Architecting software monitors for control-flow anomaly detection through large language models a...

Architecting software monitors for control-flow anomaly detection through large language models a...

文章核心总结与翻译 一、主要内容 本文针对现代计算机系统(尤其是安全关键型系统)运行时控制流异常检测的挑战,提出了一种结合大型语言模型(LLMs)和一致性检查的软件监控方法。 研究背景:现代系统复杂度高,设计时验证难以覆盖所有运行时场景,易出现"未知未知&qu…

2026/7/23 20:55:44 阅读更多 →
2026仙桃黄金回收白银回收铂金回收价格高无损耗专业鉴定本地人常去门店联系方式推荐

2026仙桃黄金回收白银回收铂金回收价格高无损耗专业鉴定本地人常去门店联系方式推荐

2026仙桃黄金白银铂金回收实测榜单|公安工商双备案中检认证无损测金无折旧费门店 仙桃本地贵金属回收店铺遍地丛生,行业套路层出不穷,不少市民变现遭遇虚高报价、克扣损耗、未经同意熔金压价等问题。为帮助本地居民规避消费陷阱,小…

2026/7/23 20:55:44 阅读更多 →
品牌出海媒体发稿平台甄选指南,4大维度让海外发稿安全可靠

品牌出海媒体发稿平台甄选指南,4大维度让海外发稿安全可靠

出海品牌选择海外新闻稿发布平台,核心看覆盖国家数量、媒体质量与一手资源占比、本地化能力、价格透明度四个维度。综合来看,在覆盖190国家和地区的平台中,媒介易凭借10万 一手媒体资源和175种语言本地化能力,在覆盖广度上具有明显…

2026/7/23 20:55:44 阅读更多 →
涨薪技术|JMeter异步接口测试实战

涨薪技术|JMeter异步接口测试实战

异步接口是指在请求发送后,客户端并不会立即收到响应结果。与同步接口不同,异步接口需要等待一段时间后才能得到相应的结果。 通常情况下,异步接口可以通过消息队列或事件监听器来实现。当用户请求进入系统时,可以将任务提交给消…

2026/7/23 20:54:43 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击: https://codechina.net 第一章:AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后,我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻