尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Qt信号槽的几种连接方式:AutoConnection/DirectConnection/QueuedConnection/BlockingQueuedConnection

Qt信号槽的几种连接方式:AutoConnection/DirectConnection/QueuedConnection/BlockingQueuedConnection
📅 发布时间:2026/7/7 2:08:35

目录

前言

Qt信号槽的5种连接方式

AutoConnection:自动连接

DirectConnection:直连

QueuedConnection:队列连接

BlockingQueuedConnection:阻塞队列连接

UniqueConnection:唯一连接

几种连接方式对比

一个包含5种连接方式的完整示例

总结

参考链接


非AI生成,觉得有用,就请您帮忙点赞转发收藏吧,您的鼓励是我创作的动力,多谢看官。

  • 前言

    Qt的信号槽机制是Qt的最显著特征,信号和槽函数是通过connect函数连接的。由于信号的发送线程和接收线程可能不同,Qt5提供了5种信号槽连接方式供程序使用,深刻理解这几种连接方式的使用场景和区别,有助于我们编写更健壮的Qt程序,避免一些不必要的麻烦。
  • Qt信号槽的5种连接方式

    • AutoConnection:自动连接

      若信号发送者和接收者在相同线程,使用DirectConnection;若信号发送者和接收者在不同线程,使用QueueConnection。
    • DirectConnection:直连

      信号发送者和接收者在相同线程,发射信号后,立即在当前线程同步调用槽函数,如果槽函数还没执行完成,则会造成线程阻塞。
      槽函数在发射信号的线程执行,多线程使用直连模式风险很高。
      如果槽函数操作了UI,就相当于在子线程操作UI,结果就是程序随机崩溃或其他非常严重的问题,UI只能在主线程操作,子线程绝对不能操作UI,这是Qt的铁律。
      多线程信号槽连接严禁使用直连方式。
    • QueuedConnection:队列连接

      多线程首选队列连接方式,槽函数在接收者所在线程执行,不阻塞发送者线程。
      信号发射是“立刻完成的”,槽函数执行是“延后的、由接收者的事件循环调度的”。
      Qt::QueuedConnection的信号发射只是向接收者线程投递一个事件,槽函数只有在接收者线程的事件循环轮询并处理该事件时才会执行。
    • BlockingQueuedConnection:阻塞队列连接

      多线程备选连接方式,阻塞的是“信号发送者所在的线程”,而不是接收者线程。
      具体机制如下:
      1.发送者线程阻塞:当发射信号时,发送者线程会把事件投递到接收者线程的事件队列,然后自身通过内部信号量(QSemaphore)进入阻塞等待状态,不会继续执行后面的代码。
      2.接收者线程正常执行:接收者线程的事件循环照常取出该事件,在接收者所在线程执行槽函数。槽函数执行完毕后,内部会释放信号量通知发送者线程。
      3.解除阻塞:接收者槽函数返回后,发送者线程被唤醒,从 emit处继续执行。
      特别注意:必须跨线程,发送者和接收者绝对不能在同一个线程,否则发送者线程会等自己处理事件,导致死锁。
      慎用场景:常用于需要跨线程同步结果的场景,但因容易引发死锁或界面卡顿(如子线程阻塞主线程),日常应优先使用普通的 Qt::QueuedConnection。
    • UniqueConnection:唯一连接

      Qt 信号槽机制中的特殊标志位,用于确保‌相同的发送者、信号、接收者和槽之间仅建立一次连接‌,重复调用connect会失败并返回false,从而防止重复触发和内存泄漏 。‌‌
    • 几种连接方式对比

  • 一个包含5种连接方式的完整示例

  • #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QThread> #include <QMutex> #include <QPointer> #include <QMessageBox> #include "Utility.h" #include "Worker.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_btnSetConnectionType_clicked(); private: Ui::MainWindow *ui; QThread* m_thread = nullptr; Worker* m_worker = nullptr; QPointer<QThread> m_thread_guard = nullptr; QPointer<Worker> m_worker_guard = nullptr; private: bool stop(); void startConnectionTest(); private slots: void onMessageReceived(ThreadType threadType,const QString& msg); void on_btnClear_clicked(); }; #endif // MAINWINDOW_H
    #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::startConnectionTest() { int itemIndex = ui->combConnType->currentIndex(); QString itemText = ui->combConnType->currentText(); itemText = QString("信号槽连接方式:%1").arg(itemText); Qt::ConnectionType connType = Qt::AutoConnection; switch (itemIndex) { case 0: connType = Qt::AutoConnection; break;//槽函数自动选择执行的线程 //槽函数在发射信号的线程执行,多线程使用直连模式风险很高 //如果槽函数操作了UI,就相当于在子线程操作UI,结果就是程序随机崩溃或其他非常严重的问题,UI只能在主线程操作,子线程绝对不能操作UI,这是Qt的铁律 //多线程信号槽连接严禁使用直连方式 case 1: connType = Qt::DirectConnection; break; //多线程首选队列连接方式,槽函数在接收者所在线程执行,不阻塞发送者线程 //信号发射是“立刻完成的”,槽函数执行是“延后的、由接收者的事件循环调度的” //Qt::QueuedConnection的信号发射只是向接收者线程投递一个事件,槽函数只有在接收者线程的事件循环轮询并处理该事件时才会执行。 case 2: connType = Qt::QueuedConnection; break; //多线程次选连接方式,阻塞的是“信号发送者所在的线程”,而不是接收者线程 //特别注意:必须跨线程,发送者和接收者绝对不能在同一个线程,否则发送者线程会等自己处理事件,导致死锁。 //慎用场景:常用于需要跨线程同步结果的场景,但因容易引发死锁或界面卡顿(如子线程阻塞主线程),日常应优先使用普通的 Qt::QueuedConnection /* 具体机制如下: 发送者线程阻塞:当发射信号时,发送者线程会把事件投递到接收者线程的事件队列,然后自身通过内部信号量(QSemaphore)进入阻塞等待状态,不会继续执行后面的代码。 接收者线程正常执行:接收者线程的事件循环照常取出该事件,在接收者所在线程执行槽函数。槽函数执行完毕后,内部会释放信号量通知发送者线程。 解除阻塞:接收者槽函数返回后,发送者线程被唤醒,从 emit处继续执行。 */ case 3: connType = Qt::BlockingQueuedConnection; break; case 4: connType = Qt::UniqueConnection; break; default:connType = Qt::AutoConnection;break; } if(1 == itemIndex){ QMessageBox::critical(this,"系统提示","多线程使用DirectConnection连接信号槽是高危行为,会导致程序闪退\n您头铁要试试看吗"); } onMessageReceived(ThreadType::UnKnown,itemText); m_thread = new QThread; m_worker = new Worker(nullptr,"Worker1",5,ThreadType::MoveToThread);//parent必须传nullptr,否则会违背Qt的线程亲和性规则,出现各种严重问题 connect(m_thread,&QThread::started,m_worker,&Worker::Start); connect(m_worker,&Worker::messageReceived,this,&MainWindow::onMessageReceived,connType); m_worker_guard = m_worker;//使用QPointer<Worker>防悬空指针误用 m_thread_guard = m_thread;//使用QPointer<QThread>防悬空指针误用 connect(m_worker,&Worker::finished,this,[=](){ if(m_worker_guard){ m_worker_guard->deleteLater(); QString msg = QString("%1 Worker对象释放成功").arg(Utility::getNowTimeStrWithMs()); onMessageReceived(ThreadType::UnKnown,msg); } if(m_thread_guard){ m_thread_guard->quit(); } }); connect(m_thread,&QThread::finished,this,[=](){ if(m_thread_guard){ m_thread_guard->deleteLater(); QString msg = QString("%1 QThread对象释放成功").arg(Utility::getNowTimeStrWithMs()); onMessageReceived(ThreadType::UnKnown,msg); } }); m_worker->moveToThread(m_thread); m_thread->start(); } void MainWindow::onMessageReceived(ThreadType threadType, const QString &msg) { static QMutex mutex; QMutexLocker<QMutex> locker(&mutex); ui->tbLog->appendPlainText(msg); } void MainWindow::on_btnSetConnectionType_clicked() { if(stop()){ startConnectionTest(); } } //不建议强制停止正在运行的线程,容易出现内存泄漏或其他问题 bool MainWindow::stop() { if(m_thread_guard){ if(m_thread_guard->isRunning()){ QMessageBox::information(this,"系统提示","线程正在执行,请等待线程执行完成"); return false; } m_thread_guard->quit(); m_thread_guard->wait(); } else{ qDebug()<<"QThread对象已经释放了,可以安全开启新线程了"; return true; } return false; } void MainWindow::on_btnClear_clicked() { ui->tbLog->clear(); }
  • 总结

    如果能确定信号发送线程和接收线程,可以明确指定连接方式,大多数场景可以使用Qt::AutoConnection,Qt会自动帮您选择连接方式。
  • 参考链接

    别再乱连了!Qt信号槽重复连接的坑,我用Qt::UniqueConnection帮你填平
    深入解析 QObject::connect 的五种连接类型

相关新闻

  • 2026年国产大模型API价格横评:DeepSeek/Kimi/GLM/Qwen哪家最便宜?附迁移避坑指南
  • 06-高级模式与实战项目——09. 单元测试 - Jest
  • 储能沙盘模型BMS功能模拟控制系统设计与实现:电压监测、均衡管理与故障保护的STM32方案

最新新闻

  • 变电设备动态实景映射,电力场站视频孪生设备隐患智能识别算法
  • 2026企业AI Agent平台选型参考:五款差异化智能体覆盖不同规模企业需求
  • 光刻 vs 刻蚀 vs 沉积:芯片制造 3 大核心工艺的技术原理与设备对比
  • 矩阵世界的“数字1”:理解线性代数中的单位矩阵
  • Spring AOP 顺序问题:切面都生效了,不代表顺序对
  • Agentic 范式下的视频画质优化:火山引擎的新路径

日新闻

  • Android逆向分析全能助手:集成化工具链与自动化工作流设计
  • 面搜索(Faceted Search)原理与工程实践指南
  • 神经网络调参避坑指南:从5个常见Loss曲线形态定位超参数问题

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号