Qt - 信号与槽的第五个参数

news/2024/11/14 5:29:14/文章来源:https://www.cnblogs.com/zhuchunlin/p/18541548

connent函数第五个参数的作用

connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

第五个参数代表槽函数在哪个线程中执行 :

自动连接(Qt::AutoConnection),默认的连接方式,如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;如果发送者与接收者处在不同线程,等同于队列连接

  • 在你的具体情况下,如果子线程发射信号,并且该信号的接收者是主线程中的一个对象,同时主线程运行着事件循环,那么槽函数将在主线程中执行

直接连接(Qt::DirectConnection - 同步),当信号发射时,槽函数立即直接调用。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行,即槽函数和信号发送者在同一线程

  • 如果信号发射者和槽接收者位于不同的线程中,并且你使用了 Qt::DirectConnection,那么就会违反 Qt 的线程安全规则,因为直接调用可能会在不同线程之间造成竞争条件或数据损坏。

队列连接(Qt::QueuedConnection - 异步),当Thread1触发信号后,信号会在处理完前面的任务后再调用相应的槽函数,槽函数在接收者线程中执行,Thread1立即会执行下面任务,无需等待接收者线程执行槽函数完毕。

锁定队列连接(Qt::BlockingQueuedConnection - 阻塞):槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

 


自动连接(Qt::AutoConnection)

  • 自动连接(Qt::AutoConnection),默认的连接方式,如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;如果发送者与接收者处在不同线程,等同于队列连接

 


直接连接(Qt::DirectConnection - 同步)

同线程

mainwindow.cpp(主线程)

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QThread>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);connect(this,SIGNAL(sig()),this,SLOT(slot()),Qt::DirectConnection);emit sig();for(int i=0; i<10;i++){qDebug() << i;}
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::slot()
{qDebug()<<"执行槽函数";
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "thread1.h"namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();private:Ui::MainWindow *ui;    private slots:void slot();
signals:void sig();
};#endif // MAINWINDOW_H

结论:发射信号后立马执行槽函数。

 

不同线程

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);qDebug()<<u8"主线程ID"<<QThread::currentThreadId();connect(&m_thread1,SIGNAL(sigThread1()),this,SLOT(slot()),Qt::DirectConnection);m_thread1.start();
}
MainWindow::~MainWindow()
{delete ui;
}
void MainWindow::slot()
{qDebug()<<u8"执行槽函数---线程ID"<<QThread::currentThreadId();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <thread1.h>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();private:Ui::MainWindow *ui;Thread1 m_thread1;private slots:void slot();// 在主函数中定义需要调用的槽函数
};#endif // MAINWINDOW_H

thread1.cpp

#include "thread1.h"
#include <QDebug>Thread1::Thread1(QThread *parent): QThread(parent)
{}void Thread1::run()
{qDebug()<<u8"Thread1线程ID"<<QThread::currentThreadId();emit sigThread1();for(int i=0;i<10;i++){qDebug()<<i;}
}

thread1.h

#ifndef THREAD1_H
#define THREAD1_H#include <QThread>class Thread1 : public QThread
{Q_OBJECT
public:explicit Thread1(QThread *parent = 0);protected:virtual void run();signals:void sigThread1();
};
#endif // THREAD1_H

结论:可以看出:emit发射信号后立马执行槽函数,没有任何等待;并且槽函数执行在Thread1线程中;

 


队列连接(Qt::QueuedConnection - 异步)

同一线程

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QThread>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);connect(this,SIGNAL(sig()),this,SLOT(slot()),Qt::QueuedConnection);emit sig();for(int i=0; i<10;i++){qDebug()<<i;}
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::slot()
{qDebug()<<u8"执行槽函数";
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "thread1.h"namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();private:Ui::MainWindow *ui;private slots:void slot();
signals:void sig();
};#endif // MAINWINDOW_H

结论:可以看到:先执行完for循环(先把自己的事情处理完),当空闲后再执行槽函数。 

 

 

不同线程

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);qDebug()<<u8"主线程ID"<<QThread::currentThreadId();connect(&m_thread1,SIGNAL(sigThread1()),this,SLOT(slot()),Qt::QueuedConnection);m_thread1.start();
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::slot()
{qDebug()<<u8"执行槽函数---线程ID"<<QThread::currentThreadId();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <thread1.h>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();private:Ui::MainWindow *ui;Thread1 m_thread1;private slots:void slot();};
#endif // MAINWINDOW_H

thread1.cpp

#include "thread1.h"
#include <QDebug>Thread1::Thread1(QThread *parent): QThread(parent)
{}
void Thread1::run()
{qDebug()<<u8"Thread1线程ID"<<QThread::currentThreadId();emit sigThread1();for(int i=0;i<10000;i++) //此处为10000次,加长时间,以便更清楚的观察现象{qDebug()<<i;}
}

thread1.h

#ifndef THREAD1_H
#define THREAD1_H#include <QThread>class Thread1 : public QThread
{Q_OBJECT
public:explicit Thread1(QThread *parent = 0);protected:virtual void run();signals:void sigThread1();
};#endif // THREAD1_H

结论:

  • 可以看出:thread1线程发送信号后,thread1接着做自己的事,主线程同样接着做自己的事。
  • 当主线程空闲时,再执行槽函数,槽函数运行在主线程中。

 


锁定队列连接(Qt::BlockingQueuedConnection - 阻塞)

  • 代码参考上面的,将Qt::QueuedConnection改为Qt::BlockingQueuedConnection即可。
  • 可以看到:规律同Qt::QueuedConnection,不过thread1线程发送完信号后,会阻塞,直到主线程的槽函数返回,thread1线程才会继续向下执行。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/832214.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

团队作业4——项目冲刺

团队作业4——项目冲刺这个作业属于哪个课程 <计科22级34班>这个作业要求在哪里 <作业要求>这个作业的目标 修改完善需求规格说明书、系统设计、Alpha任务分配计划、测试计划GitHub 链接 https://github.com/tangliweiwww/ChatGpt🍟一、团队 1.团队名称:Eleganc…

Maven打包项目的精准指定——流程管理

作用Maven不仅可以进行依赖管理的自动化,还可以自动化实现编译,打包,发布,等,也被成为构建流程 生命周期(lifecycle) 构成Maven生命周期本身可以看做一个集合,在这个集合中包含了一系列阶段(phase)。也就是说Maven的生命周期由一系列阶段(phase)构成但是话又说回来…

如何正确导入mapstruct,同时避免编译时mapstruct与lombok冲突

本文介绍编译时产生的冲突,导包时期产生的冲突请劳驾查找其他解决方法一般情况下只需要按照官网的导入即可,但如果同时使用了lombok,则需要小心。详细信息可以查看官网文档:MapStruct 1.5.5.Final 集成lombok注意:在编译测试的时候,一定先清理再编译。这样可以解决80%的报…

施耐德UNITY下使用ST编程计算最近一小时的均值

昨晚学习练习了ST语言做最近60秒的分钟均值,今天继续做最近一小时的均值,1秒采集一次数据。在昨晚程序上增加功能,新建一个导出的功能块类型Average_Hour,定义下面的变量:旗下新建一个程序段Average_Hour,使用ST编程 Minute1:=BCD_TO_INT(%SW51);Minute:=mod_int(Minute1…

HyperWorks使用六面体和三棱柱单元进行实体网格剖分

本节将演示如何使用 solid map 功能对一个复杂的几何实体进行网格剖分。剖分的思路是:首先对该实体进行适当的切割,以使其各个部分均处于 mappable 的状态;然后分别对各个子块进行 solid map 剖分。事实上,针对同一个几何实体,可能有多种分块方案。究竟哪种方案能获得更高…

SQLSever将csv文件中的数据导入数据库中的某个表中的操作以及可能会出现的报错

注:导入数据前,检查一下数据类型是否与数据库中的数据类型相匹配 第一种方法: 首先打开SQLSever数据库,右击你的数据库找到任务后点开导入平面文件,如图 在弹开的窗口中点击下一步 接下来 填写完后点击下一步,跳转到预览数据的页面,会显示出表中的前20条数据,在检查没有…

云消息队列 Kafka 版全面升级:经济、弹性、稳定,成本比自建最多降低 82%

本文整理于 2024 年云栖大会阿里云智能集团产品专家张凤婷带来的主题演讲《云消息队列 Kafka 版全面升级:经济、弹性、稳定》作者:娜米 本文整理于 2024 年云栖大会阿里云智能集团产品专家张凤婷带来的主题演讲《云消息队列 Kafka 版全面升级:经济、弹性、稳定》 云原生消息…

Java定时任务大盘点:发工资也能“指日可待”

作者:京东保险 孙昊宇 引子:“指日可待”让我们先从一个成语开始,“指日可待”。没错,我说的就是定时任务😏。“指日可待”: 为任务指定好日程,就可以安心等待任务执行。在实际场景中,我们往往需要在特定时间做某件事情,或以某个时间间隔重复某件事情,如定期备份数据…

B端体验深耕-洞察用户需求,打造心有灵犀的使用体验

作者:京东科技 程跃宇前言 我们常以“心有灵犀”来形容与合作伙伴的默契配合,若我们的产品能与用户达到同样的默契,将极大地提升用户在任务旅程中的流畅体验。 在B端体验设计领域,我们深知用户对我们产品的期待───快速完成任务、即用即走;然而,随着业务需求和产品功能…

YLCTF RE

Round1 [Round 1] xor kail upx脱壳,一眼顶针,xor v5 = [0x45, 0x50, 0x5f, 0x48, 0x5a, 0x67, 0x7f, 0x2d, 0x2b, 0x7e, 0x24, 0x78, 0x2c, 0x24, 0x31, 0x2c, 0x7e, 0x78, 0x24,0x31, 0x28, 0x2d, 0x7a, 0x7d, 0x31, 0x7e, 0x25, 0x79, 0x2b, 0x31, 0x29, 0x79, 0x2a, 0x2f…

RAG应用性能优化全景图:从查询到生成的6个关键阶段

引言 检索增强生成(Retrieval-Augmented Generation,RAG)技术已成为大语言模型(LLM)应用开发中的关键组成部分。然而,构建高效、准确的RAG系统仍然面临诸多挑战。本文将深入探讨RAG开发的6个关键阶段,并分析每个阶段的优化策略,为开发者提供全面的性能优化指南。 RAG开…

html 空白汉字占位符

符号表示&nbsp; 英文半角空格不换行&#160; 英文半角空格不换行&#12288; 中文全角空格&ensp; 半角空格&#8194; 半角空格&#8195; 全角空格&emsp; 全角空格&#8197; 四分之一全角空格&#32; 英文半角空格连续的&nbsp;会在同一行内…