Qt 死锁避坑实录:从一段“看起来很 Qt”的代码说起
目录一、先给结论二、一段“看起来完全没问题”的死锁代码1.场景设定2.死锁复现代码精简版3.Worker 实现死锁核心三、为什么直接死锁Qt 特有版1️. AutoConnection 在这里是 QueuedConnection2️. 发生了什么四、更隐蔽的变种deleteLater 锁Qt 老坑五、正确解法一最推荐emit 前解锁原则信号 通知不是同步调用六、解法二明确 QueuedConnection 拷贝数据线程安全版七、解法三用 QAtomic轻量场景八、解法四QObject 线程边界法则高级一个对象只被一个线程“操作”九、Qt 死锁预防清单十、最终推荐模板十一、一句话总结觉得有用就请您帮忙点赞转发收藏吧您的鼓励是我创作的动力多谢看官。由于能力水平有限文中的错误或不严谨的地方在所难免还请批评指正。摘要Qt 多线程里 90% 的死锁都不是“写错了锁”而是信号槽 QObject::thread() 隐式队列锁 递归 mutex​ 共同制造出来的。本文用一段真实感极强的 Qt 风格代码复现死锁拆解 Qt 特有的Event Loop / QueuedConnection / 跨线程 delete / QMutex 递归陷阱并给出 4 种可落地的工程级解决方案。看完你会明白为什么QMutexLocker救不了你deleteLater()反而救了你。一、先给结论Qt 中预防死锁记住这 5 条比背《操作系统死锁四条件》有用锁永远不要跨 event loop 边界持有QueuedConnection 回调里不拿别的线程的锁一个线程 一个 QMutex 责任域不要“共享对象 共享锁”emit signal 前能 unlock 就 unlock跨线程 delete / access 对象 → 只用deleteLater()下面用代码说话。二、一段“看起来完全没问题”的死锁代码1.场景设定Worker 在子线程干活MainThread 发命令用QMutex保护共享数据用 signal/slot 通知状态2.死锁复现代码精简版// data.h struct SharedData { QMutex mutex; int value 0; }; // worker.h class Worker : public QObject { Q_OBJECT public slots: void doWork(); signals: void progress(SharedData *data); }; // main thread SharedData data; Worker *worker new Worker; QThread *th new QThread; worker-moveToThread(th); connect(th, QThread::started, worker, Worker::doWork); connect(worker, Worker::progress, [](SharedData *d){ d-mutex.lock(); // 子线程已经获取锁还在摸鱼没释放呢主线程又想获取锁相当于先后调用了两次lock()程序必死锁 qDebug() UI read: d-value; d-mutex.unlock(); }); th-start();3.Worker 实现死锁核心void Worker::doWork() { >三、为什么直接死锁Qt 特有版1️. AutoConnection 在这里是 QueuedConnection因为worker-moveToThread(th);所以emit progress() → Worker(子线程) → MainThread → Qt 帮你 queue 一个 meta call2️. 发生了什么执行顺序时间线程行为T1Workermutex.lock()T2Workeremit progress()→ post event 到 main threadT3Mainevent loop 处理 signalT4Mainlambda 里mutex.lock()阻塞​T5Worker等 main thread 处理完 signalT6Worker永远等不到 mutex经典死锁四条件 Qt 版达成互斥占有且等待 子线程占锁等 main不可抢占 QMutex 默认循环等待 main ↔ worker四、更隐蔽的变种deleteLater 锁Qt 老坑void Worker::doWork() { QMutexLocker locker(data-mutex); >五、正确解法一最推荐emit 前解锁原则信号 通知不是同步调用void Worker::doWork() { { QMutexLocker locker(data-mutex); >六、解法二明确 QueuedConnection 拷贝数据线程安全版signals: void progress(int value); // 简单数据传值不传指针void Worker::doWork() { int v; { QMutexLocker locker(data-mutex); >七、解法三用 QAtomic轻量场景QAtomicInt value; void Worker::doWork() { emit progress(value.fetchAndAddRelaxed(10) 10); }无锁不适合复杂结构八、解法四QObject 线程边界法则高级一个对象只被一个线程“操作”class Worker : public QObject { Q_OBJECT QMutex mutex; public: void safeAdd(); };规则Worker 永远只在自己线程操作 mutexUI 想读→ signal / invokeMethodQueuedQMetaObject::invokeMethod(worker, []{ worker-safeAdd(); // ✅ 在自己线程跑 }, Qt::QueuedConnection);本质用 event loop 当锁九、Qt 死锁预防清单1️.QMutex 只保护数据不保护逻辑​2️.emit signal 时手里不能握着任何线程的锁​3️.AutoConnection 是 Qt 给你埋的雷跨线程就当它是 Queued​4️.deleteLater() 是 Qt 线程安全最后的尊严​5️.event loop 能解决的同步就别用 mutex十、最终推荐模板void Worker::doWork() { // 1. 锁最小作用域 int snapshot; { QMutexLocker locker(m_mutex); m_data.value 1; snapshot m_data.value; } // 2. emit 无锁 emit progress(snapshot); // 3. 耗时操作 heavyTask(); }十一、一句话总结Qt 的死锁大多不是多线程问题而是你以为 Qt 帮你串行化了逻辑其实它只是帮你排了个队。真正的 Qt 并发安全不是“锁住一切”而是让对象只活在一个线程里剩下的交给 signal / event loop / deleteLater。

相关新闻

5分钟上手D2RML多开工具,让暗黑2重制版多账号登录告别手动换号

5分钟上手D2RML多开工具,让暗黑2重制版多账号登录告别手动换号

5分钟上手D2RML多开工具,让暗黑2重制版多账号登录告别手动换号 【免费下载链接】D2RML Diablo 2 Resurrected Multilauncher 项目地址: https://gitcode.com/gh_mirrors/d2/D2RML 玩暗黑破坏神2重制版(D2R)的人,多半经历过…

2026/10/12 2:17:16 阅读更多 →
ReadCat 免费开源小说阅读器:告别广告,把阅读还给文字

ReadCat 免费开源小说阅读器:告别广告,把阅读还给文字

ReadCat 免费开源小说阅读器:告别广告,把阅读还给文字 【免费下载链接】read-cat 一款免费、开源、简洁、纯净、无广告的小说阅读器 项目地址: https://gitcode.com/gh_mirrors/re/read-cat 晚上十一点半,你点开阅读 App 追更&#xf…

2026/10/6 18:16:35 阅读更多 →
惠普暗影精灵性能释放指南:用 OmenSuperHub 接管风扇、功耗与灯光(附完整上手教程)

惠普暗影精灵性能释放指南:用 OmenSuperHub 接管风扇、功耗与灯光(附完整上手教程)

惠普暗影精灵性能释放指南:用 OmenSuperHub 接管风扇、功耗与灯光(附完整上手教程) 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://git…

2026/10/9 9:04:32 阅读更多 →

最新新闻

Photoshop移动UI设计从入门到精通:画布搭建、控件绘制与切图导出全流程

Photoshop移动UI设计从入门到精通:画布搭建、控件绘制与切图导出全流程

简介:这份PPT讲义面向移动UI设计初学者与希望系统提升的设计师,围绕Photoshop在移动端界面设计中的应用展开,帮助读者从零建立移动UI设计认知并逐步进阶。内容按模块递进:新手导航讲解手机与平板界面差异、iOS/Android/Windows Ph…

2026/10/14 12:58:58 阅读更多 →
MCP Python SDK:模型上下文协议的高效实现与应用

MCP Python SDK:模型上下文协议的高效实现与应用

1. 项目概述:MCP Python SDK 是什么? 在当今数据驱动的技术环境中,模型上下文协议(Model Context Protocol,简称MCP)正逐渐成为连接机器学习模型与实际业务场景的关键桥梁。作为一名长期从事AI工程化的开发…

2026/10/14 12:58:58 阅读更多 →
PyInstaller 3.2.1实战:老版本打包器解决Python旧工程分发难题

PyInstaller 3.2.1实战:老版本打包器解决Python旧工程分发难题

简介:PyInstaller 3.2.1是一份面向Python开发者的跨平台打包工具资源,旨在解决Python程序在无解释器环境下的分发难题,适合需要将脚本封装为独立可执行文件的入门及进阶用户。压缩包内含790个文件,约3.01MB,以py源码、…

2026/10/14 12:58:58 阅读更多 →
微信小程序在线选课系统开发实战

微信小程序在线选课系统开发实战

1. 项目背景与核心价值微信小程序在线选课系统是当前教育信息化领域的热门解决方案。作为一名参与过多个校园信息化项目的开发者,我发现传统选课系统存在几个痛点:学生需要在特定时间段挤爆机房电脑、移动端适配差、高峰期服务器容易崩溃。而基于微信小程…

2026/10/14 12:58:58 阅读更多 →
一次数据建模返工,彻底理解资源-事件-参与者(REA)模型

一次数据建模返工,彻底理解资源-事件-参与者(REA)模型

从 REA 说起:一次数据建模的“返工”让我彻底理解了资源-事件-参与者模型去年年中,团队接手了一个库存管理的小型系统改造。起初我看了一眼旧数据库结构,订单表、商品表、库存表、支付表,各自挂着外键,看似井井有条。业…

2026/10/14 12:58:58 阅读更多 →
贷款违约预测实战入门:从数据处理到评分卡全流程解析

贷款违约预测实战入门:从数据处理到评分卡全流程解析

简介:面向零基础金融风控学习者,提供一份基于 Python 的贷款违约预测完整项目,聚焦个人信贷场景中的违约风险识别,适合作为课程设计或期末大作业提交。项目已获导师指导,并得到 97 分高分评价,代码与说明材…

2026/10/14 12:57:57 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →