(Qt) QThread 信号槽所在线程

news2024/9/21 18:33:58

文章目录

  • 💁🏻前言
  • 💁🏻Code
    • 💁🏻‍♂️Code
    • 💁🏻‍♂️环境
  • 💁🏻当前线程信号
    • 💁🏻‍♂️默认效果
    • 💁🏻‍♂️Qt::ConnectionType::AutoConnection
    • 💁🏻‍♂️Qt::ConnectionType::DirectConnection
    • 💁🏻‍♂️Qt::ConnectionType::QueuedConnection
  • 💁🏻外部线程的信号
    • 💁🏻‍♂️默认效果
    • 💁🏻‍♂️Qt::ConnectionType::AutoConnection
    • 💁🏻‍♂️Qt::ConnectionType::DirectConnection
    • 💁🏻‍♂️Qt::ConnectionType::QueuedConnection
  • 💁🏻END
    • 🌟关注我

💁🏻前言

在 Qt 中用一套自己的封装的多线程操作。

其中一种方式是继承 QThread 并实现 void run(); 方法使用 void start(); 启动,这是一种很常见的线程的封装方式。这种方式在 java 中也是这么设计的。

但是由于 Qt 的高度封装性和框架整体性,很多特性都是开发者自己测试出来的。

其中 QThread 配合信号槽的特性就是本文要观察的重点。

💁🏻Code

这里放一份基本的code,后面的观察都是基于具体 void QThread::run(); 的修改的观察。

本文下面默认的外部线程值得就是在 main() 中一致的线程。

💁🏻‍♂️Code

目录

C:.
└─mythread
        main.cpp
        mythread.cpp
        mythread.h
        mythread.pro

mythread.pro

QT = core

CONFIG += c++17 cmdline

SOURCES +=      \
    main.cpp    \
    mythread.cpp

HEADERS += \
    mythread.h

main.cpp

只负责创建我们观察的实例

#include <QCoreApplication>
#include <QDebug>
#include <QThread>

#include "mythread.h"

int main(int argc, char* argv[]) {
    QCoreApplication a(argc, argv);
    qDebug() << "Main Thread" << QThread::currentThread();

    MyThread myth;
    qDebug() << "Object-Thread" << myth.thread();

    return a.exec();
}

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class MyThread : public QThread {
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);

protected:
    void run() override;

signals:
    void signal_test();
};

#endif  // MYTHREAD_H

mythread.cpp

在构造中就启动线程。(主要是想把所有操作都几种在一个文件中,不影响测试的效果个逻辑)

在槽函数的事件中,再次发出信号,查看连续的信号槽的效果。

#include "mythread.h"

#include <QDebug>
#include <QThread>
#include <QTimer>

MyThread::MyThread(QObject *parent) : QThread{parent} {
    qDebug() << QString("Construction-Line[%1]").arg(__LINE__) << QThread::currentThread();
    start();

    // QTimer::singleShot(100, this, [this]() { emit signal_test(); });
}

void MyThread::run() {
    qDebug() << QString("Run-Line[%1]").arg(__LINE__) << QThread::currentThread();

    auto task = [this]() {
        qDebug() << QString(">>>Line[%1]").arg(__LINE__) << QThread::currentThread();

        QThread::sleep(1);
        emit signal_test();
    };

    connect(this, &MyThread::signal_test, task);
    // emit signal_test();

    qDebug() << QString("Run-Line[%1]").arg(__LINE__) << QThread::currentThread();
    exec();
}

当前模板下的测试样例效果:

由于这是一个不会自己终止的程序,因此下文中打印的效果仅截取关键部分表示示意。

Main Thread QThread(0x11072c8)
"Construction-Line[8]" QThread(0x11072c8)
Object-Thread QThread(0x11072c8)
"Run-Line[15]" MyThread(0x76fe70)
"Run-Line[27]" MyThread(0x76fe70)

💁🏻‍♂️环境

本文测试环境:Qt 5.15.2 MinGW 32-bit

下面放两个版本的 connect 的实现方式。

// 该 connect 的实现如下
connect(this, &MyThread::signal_test, task);

// Qt 5.15.2
//connect to a functor
template <typename Func1, typename Func2>
static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
        connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
{
    return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection);
}

// Qt 6.7.2
inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,
                                            const char *amember, Qt::ConnectionType atype) const
{ return connect(asender, asignal, this, amember, atype); }

💁🏻当前线程信号

解开 void run(); 函数中的信号发送。

效果

根据不同的 connect,不只是最后一个连接类型 ConnectionType

槽函数可能在子线程,可能在主线程执行。

💁🏻‍♂️默认效果

void MyThread::run() {
    qDebug() << QString("Run-Line[%1]").arg(__LINE__) << QThread::currentThread();

    auto task = [this]() {
        qDebug() << QString(">>>Line[%1]").arg(__LINE__) << QThread::currentThread();

        QThread::sleep(1);
        emit signal_test();
    };

    connect(this, &MyThread::signal_test, task);
    emit signal_test();

    qDebug() << QString("Run-Line[%1]").arg(__LINE__) << QThread::currentThread();
    exec();
}
Main Thread QThread(0x12372c8)
"Construction-Line[8]" QThread(0x12372c8)
Object-Thread QThread(0x12372c8)
"Run-Line[15]" MyThread(0x76fe70)
">>>Line[18]" MyThread(0x76fe70)
">>>Line[18]" MyThread(0x76fe70)

效果

直接在当前线程中,发送信号,并默认的绑定 connect 是直接执行槽函数的,并槽函数执行线程是子线程。

并且由于在槽函数继续发送信号,导致下面的 qDebug() 没有打印。

💁🏻‍♂️Qt::ConnectionType::AutoConnection

connect(this, &MyThread::signal_test, QThread::currentThread(), task, Qt::ConnectionType::AutoConnection);
Main Thread QThread(0x11b72c8)
"Construction-Line[8]" QThread(0x11b72c8)
Object-Thread QThread(0x11b72c8)
"Run-Line[15]" MyThread(0x76fe70)
"Run-Line[27]" MyThread(0x76fe70)
">>>Line[18]" QThread(0x11b72c8)
">>>Line[18]" QThread(0x11b72c8)

效果

执行到 exec(), 槽函数在主线程执行。

效果同 Qt::ConnectionType::QueuedConnection

💁🏻‍♂️Qt::ConnectionType::DirectConnection

connect(this, &MyThread::signal_test, QThread::currentThread(), task, Qt::ConnectionType::DirectConnection);
Main Thread QThread(0x9372c8)
"Construction-Line[8]" QThread(0x9372c8)
Object-Thread QThread(0x9372c8)
"Run-Line[15]" MyThread(0x76fe70)
">>>Line[18]" MyThread(0x76fe70)
">>>Line[18]" MyThread(0x76fe70)

效果

在执行 exec() 前就触发槽函数。即槽函数在子线程中运行。

💁🏻‍♂️Qt::ConnectionType::QueuedConnection

connect(this, &MyThread::signal_test, QThread::currentThread(), task, Qt::ConnectionType::QueuedConnection);
Main Thread QThread(0x11e72c8)
"Construction-Line[8]" QThread(0x11e72c8)
Object-Thread QThread(0x11e72c8)
"Run-Line[15]" MyThread(0x76fe70)
"Run-Line[27]" MyThread(0x76fe70)
">>>Line[18]" QThread(0x11e72c8)
">>>Line[18]" QThread(0x11e72c8)

效果

执行到 exec(), 槽函数在主线程执行。

💁🏻外部线程的信号

在构造中直接启动线程,并在构造的线程中发送一个信号。

为什么要加一个定时器,因为要等待事件循环(Qt基础,不过多解释)。

MyThread::MyThread(QObject *parent) : QThread{parent} {
    qDebug() << QString("Construction-Line[%1]").arg(__LINE__) << QThread::currentThread();
    start();

    QTimer::singleShot(100, this, [this]() { emit signal_test(); });
}

效果

下方测试:均执行到 exec() 槽函数在主线程执行。

💁🏻‍♂️默认效果

void MyThread::run() {
    qDebug() << QString("Run-Line[%1]").arg(__LINE__) << QThread::currentThread();

    auto task = [this]() {
        qDebug() << QString(">>>Line[%1]").arg(__LINE__) << QThread::currentThread();

        QThread::sleep(1);
        emit signal_test();
    };

    connect(this, &MyThread::signal_test, task);
    // emit signal_test();

    qDebug() << QString("Run-Line[%1]").arg(__LINE__) << QThread::currentThread();
    exec();
}
Main Thread QThread(0xa772c8)
"Construction-Line[8]" QThread(0xa772c8)
Object-Thread QThread(0xa772c8)
"Run-Line[15]" MyThread(0x76fe70)
"Run-Line[27]" MyThread(0x76fe70)
">>>Line[18]" QThread(0xa772c8)
">>>Line[18]" QThread(0xa772c8)

效果

首先,这里会保证 void run(); 可以执行到 void exec(); 所以在 exec 上面的所有代码都可以执行。

但由于是外部的信号,执行的槽函数也全部是和主线程一致的。

💁🏻‍♂️Qt::ConnectionType::AutoConnection

connect(this, &MyThread::signal_test, QThread::currentThread(), task, Qt::ConnectionType::AutoConnection);
Main Thread QThread(0x12f72c8)
"Construction-Line[8]" QThread(0x12f72c8)
Object-Thread QThread(0x12f72c8)
"Run-Line[15]" MyThread(0x76fe70)
"Run-Line[27]" MyThread(0x76fe70)
">>>Line[18]" QThread(0x12f72c8)
">>>Line[18]" QThread(0x12f72c8)

效果

执行到 exec(), 槽函数在主线程执行。

AutoConnection, DirectConnection, QueuedConnection 三者的效果一致。

💁🏻‍♂️Qt::ConnectionType::DirectConnection

connect(this, &MyThread::signal_test, QThread::currentThread(), task, Qt::ConnectionType::DirectConnection);
Main Thread QThread(0x8372c8)
"Construction-Line[8]" QThread(0x8372c8)
Object-Thread QThread(0x8372c8)
"Run-Line[15]" MyThread(0x76fe70)
"Run-Line[27]" MyThread(0x76fe70)
">>>Line[18]" QThread(0x8372c8)
">>>Line[18]" QThread(0x8372c8)

效果

执行到 exec(), 槽函数在主线程执行。

💁🏻‍♂️Qt::ConnectionType::QueuedConnection

connect(this, &MyThread::signal_test, QThread::currentThread(), task, Qt::ConnectionType::QueuedConnection);
Main Thread QThread(0x9c72c8)
"Construction-Line[8]" QThread(0x9c72c8)
Object-Thread QThread(0x9c72c8)
"Run-Line[15]" MyThread(0x76fe70)
"Run-Line[27]" MyThread(0x76fe70)
">>>Line[18]" QThread(0x9c72c8)
">>>Line[18]" QThread(0x9c72c8)

效果

执行到 exec(), 槽函数在主线程执行。

💁🏻END

🌟关注我

关注我,学习更多C/C++,算法,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RTOS(7)队列

1.队列的理论知识 下面的结构体里包含了&#xff1a;头部指针&#xff0c;写指针&#xff0c;读指针&#xff0c;长度&#xff0c;项目大小&#xff0c;两个链表&#xff1b; 写队列的时候&#xff0c;写指针指向头部&#xff0c;写进去之后&#xff0c;itemsize&#xff0c;移…

MySQL中的日志

错误日志 错误日志是MySQL中最重要的日志之一默认是开启的&#xff0c;它记录了MySQL启动和停止时&#xff0c;以及入伍再运行过程中发发生任何严重错误时的相关信息&#xff0c;当数据库出现任何故障无法正常运行时可以查看此日志。 二进制日志 二进制日志记录了所有的DDL语…

http跨域网络请求中的CORS(跨源资源共享) 那些事 -- HTTP跨域请求, chrome插件跨域请求使用详解, origin格式,origin通配符等

在我们进行网络应用开发的时候&#xff0c;如果用到了跨域网络请求&#xff0c;则不可避免的就会遇到http跨域网络请求 CORS的问题&#xff0c;今天就和大家来聊聊跨域网络请求中的CORS的那些事。 跨源资源共享&#xff08;CORS&#xff09; CORS 是一种基于 HTTP 头的机制&a…

ISO26262-MBD-静态验证在V左的布局考量

一、ISO26262-MBD-静态验证的迷惑 模型的开发方法&#xff08;Model-Based Design&#xff0c;MBD&#xff09;在汽车行业嵌入式软件开发中扮演着重要的角色&#xff0c;功能安全ISO26262要求对我们搭建的模型进行规范检查。合规检查我们可以借助第三方工具来实现静态检查&…

基于Django的图书管理系统【万能模板框架可调整增加】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主框架介绍项目框架每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 框架介绍 Django是一个用于快速开发Web应用程序的高级Python开源框架。它遵循MVC…

去除富文本框的边框

<style lang"scss" scoped>::v-deep .textareaDeep .el-textarea__inner {border: none !important;box-shadow: none !important;padding: 0px; }</style> //添加类名 <el-inputclass"textareaDeep"type"textarea":rows"…

Go语言实现依赖注入

文章目录 前言依赖注入是什么依赖注入的好处是什么结构图应用程序上下文接口上下文管理器暴露的功能使用示例最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;欢迎来到我的博客&#xff0c;今天带领大伙使用Go语言实现依赖自动注入&#xff0c;我们不会使用其它的第三方库…

域控安全:多种方式提取ntds.dit

ntdsutils.exe提取ntds.dit vssadmin提取ntds.dit vssown提取ntds.dit IFM ntds.dit: ntds.dit为AD的数据库&#xff0c;内容有域用户、域组、用户hash等信息&#xff0c;域控上的ntds.dit只有可以登录到域控的用户&#xff08;如域管用户、DC本地管理员用户&#xff09;可以…

HexView 刷写文件脚本处理工具-基本功能介绍(一)-基本界面

HexView主要可以显示不同文件格式的内容&#xff0c;包括Intel-HEX、Motorola S-record二进制文件或其他特定汽车制造商的文件格式。此外&#xff0c;它还可以执行多种数据处理操作&#xff0c;如校验和计算、签名生成、数据加密/解密或压缩/解压缩&#xff0c;甚至重新排列文件…

ubuntu创建txt

点击模版 右键 输入下面代码 sudo gedit txt文档.txt 然后就可以右键新建文本文件了 解开权限 sudo chmod -R 777 /home/sjxy/CQ

探索下一代互联网协议:IPv6的前景与优势

探索下一代互联网协议&#xff1a;IPv6的前景与优势 文章目录 探索下一代互联网协议&#xff1a;IPv6的前景与优势**IPv6 的特点****IPv6的基本首部****IPv6的地址****总结** 互联网的核心协议&#xff1a;从IPv4到IPv6 互联网的核心协议IP&#xff08;Internet Protocol&#…

【Nacos无压力源码领读】(一) Nacos 服务注册与订阅原理

本文将详细介绍 Nacos 客户端在启动时进行自动注册原理, 以及Nacos服务器是如何处理客户端的注册与订阅请求的; 本文会附带源码解读, 但不会死抠每一行代码, 主要是梳理整个流程, 过程中的关键步骤, 都会由思维导图的形式展现出来; 如果在阅读过程中对文中提到的 SpringBoot …

Comsol 弧形声学换能器声聚焦仿真

弧形声学换能器声聚焦是指将声波能量集中在弧形声学换能器的特定区域内&#xff0c;以实现更强的声场强度和分辨率。声聚焦在许多应用中非常有用&#xff0c;包括医学超声成像、声纳、声波聚焦破碎等领域。 弧形声学换能器的设计和优化可以通过以下几个因素来实现声聚焦&#…

【网站项目】SpringBoot743中珠商城仓库管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

A股破新低后震荡盘整,后市如何演绎?

今天的A股&#xff0c;让人按耐不住了&#xff0c;你们知道是为什么吗&#xff1f;盘面上出现1个重要信号&#xff0c;一起来看看&#xff1a; 1、今天两市冲高回落&#xff0c;主力压盘、故意洗筹码的意图就更加明显了&#xff0c;一定要拿住&#xff01;地板上卖出的&#xf…

《刚刚问世》系列初窥篇-Java+Playwright自动化测试-4-启动浏览器-基于Maven(详细教程)

1.简介 上一篇文章&#xff0c;宏哥已经在搭建的java项目环境中添加jar包实践了如何启动浏览器&#xff0c;今天就在基于maven项目的环境中给小伙伴们或者童鞋们演示一下如何启动浏览器。 2.eclipse中新建maven项目 1.依次点击eclipse的file - new - other &#xff0c;如下…

初阶数据结构5 排序

排序 1. 排序概念及运用1.1 概念1.2运用1.3 常见排序算法 2. 实现常⻅排序算法2.1 插⼊排序2.1.1 直接插⼊排序2.1.2 希尔排序2.1.2.1 希尔排序的时间复杂度计算 2.2 选择排序2.2.1 直接选择排序2.2.2 堆排序 2.3 交换排序2.3.1冒泡排序2.3.2 快速排序2.3.2.1 hoare版本2.3.2.2…

学习c#-4语句 ,条件,循环

代码&#xff1a; string name "小赵"; //条件判断 if (name "小赵") { Console.WriteLine("我是小赵"); } else { Console.WriteLine("我不是小赵"); } // switch条件判断 switch (name) { case "小…

【letcode-c++】283.移动零

一、题目 二、分析 题目让我们不能复制&#xff0c;只能在数组中交换移动。那么数组中的移动&#xff0c;比较方便的是前后两个元素交换&#xff0c;并且非零元素相对位置不变&#xff0c;那就考虑0和它后面的非0元素进行交换&#xff0c;进一步思考&#xff0c;除了单个0移动…

双指针习题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…