Qt多线程阻塞:为何信号失效?

这个问题问到了 Qt 多线程编程的核心机制。简单来说,是因为 "一个线程在同一时刻只能做一件事"

为了让你彻底理解,我们把线程想象成一个**"办事员",把事件循环想象成他的"工作手册"**。

1. 正常的"事件驱动"模式

在正常的 Qt 线程中,办事员的操作流程是这样的(这就是 exec() 内部做的事):

复制代码
// 简化版的事件循环逻辑 (QEventLoop)
while (true) {
    // 1. 检查有没有新邮件(信号、定时器、鼠标点击等事件)
    Event e = waitNextEvent(); 
    
    // 2. 拆开邮件,根据指令去干活
    processEvent(e); 
    
    // 3. 干完活了,回到第 1 步继续等
}

在这种情况下,办事员大部分时间都在等邮件。一旦你从主线程发一个 QueuedConnection 的信号,就相当于给他的邮箱丢了一封信。他处理完手头的微小工作后,马上就会拆信并执行 setPaused(true)


2. 为什么你的 while 循环堵死了它?

当你的代码进入了 while(!m_stop) 这种大循环(解码循环)时,办事员的状态变成了这样:

复制代码
void VideoWorker::startDecode() {
    // 办事员进入了这个房间,并反锁了门
    while (!m_stop) {
        // A. 解码一帧视频
        // B. 计算同步时间
        // C. 渲染画面
        // ... 他在这个循环里转圈圈,永远回不到上面的"检查邮件"步骤
    }
}

关键点在于:

  • 邮箱在门外: Qt::QueuedConnection 投递的事件是放在该线程的**事件队列(邮箱)**里的。

  • 没空收信: 办事员(子线程)正忙着在 while 循环里"解码",只要这个 while 循环不结束,他就没有机会 回到事件循环的 processEvent() 阶段去开邮箱。

  • 后果: 你的暂停指令(邮件)就一直堆在邮箱里,直到 while 循环因为某种原因(比如播放结束)退出了,他才会去开箱,但那时候暂停已经没意义了。


3. 图解对比

状态 线程行为 事件处理情况
空闲/标准状态 循环执行 exec() 正常。像前台文员,每干完一个杂活就看一眼信箱。
你的死循环状态 循环执行 decode() 失效。像流水线工人,手一直在动,即使信箱塞满了,他也看不见。

4. 为什么"直接调用"和"原子变量"能解决?

当你把 QueuedConnection 改成在主线程直接调用 worker->setPaused(true) 时:

  1. 不走邮箱: 主线程直接冲进子线程的房间,强行修改了桌子上的一个开关(std::atomic<bool> m_paused)。

  2. 瞬间生效: 此时子线程虽然还在 while 循环里转圈,但它下一圈跑到 waitIfPaused() 这行代码时:

    复制代码
    void waitIfPaused() {
        if (m_paused.load()) { // 这里它读到了主线程刚改掉的开关!
            // 乖乖进入阻塞等待状态
        }
    }
  3. 结果: 子线程被"绊了一跤",停在了原地。

总结

子线程不是"不执行"事件循环,而是它被你写的 while 循环给"绑架"了,导致它根本没有机会运行到 Qt 框架提供的那个负责处理事件的 while 循环里。

这也是为什么在处理密集型计算(如音视频解码、大文件读取)时,我们必须使用原子变量 (Atomic)互斥量 (Mutex) 来进行跨线程的"硬控制",而不是依赖"软绵绵"的异步信号。

相关推荐
ii_best2 小时前
「安卓开发辅助工具按键精灵」xml全分辨率插件jsd插件脚本教程
android·xml·开发语言·编辑器·安卓
李慕婉学姐2 小时前
【开题答辩过程】以《基于python的气象灾害数据分析与可视化系统》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
开发语言·python·数据分析
__万波__2 小时前
二十三种设计模式(十四)--命令模式
java·设计模式·命令模式
一起养小猫2 小时前
《Java数据结构与算法》第四篇(三)二叉树遍历详解_CSDN文章
java·开发语言·数据结构
少许极端2 小时前
算法奇妙屋(十九)-子序列问题(动态规划)
java·数据结构·算法·动态规划·子序列问题
小满、2 小时前
RabbitMQ:AMQP 原理、Spring AMQP 实战与 Work Queue 模型
java·rabbitmq·java-rabbitmq·spring amqp·amqp 协议·work queue
萧曵 丶2 小时前
Java Stream 实际用法详解
java·stream·lambda
消失的旧时光-19432 小时前
从 Android 回调到 C 接口:函数指针 + void* self 的一次彻底理解
android·c语言·开发语言
dvlinker2 小时前
动态代理技术实战测评—高效解锁Zillow房价历史
android·java·数据库