QT 多线程信号与槽(一)

2023-11-08

QT 中 QObject 作QT中类的最终父类,具有自定义信号与槽的能力,只要继承自这个类的类,也一样拥有自定义信号和槽的能力。QT 中定义信号与槽是十分有用的,那我们的线程类是不是也有这个能力呢?

查一下 QThread 的源码,我们发现 QThread 是继承自 QObject 的,他确实有自定义信号和槽的能力 !!!

class Q_CORE_EXPORT QThread : public QObject
{
	。。。
};

那他有没有已经定义好的方便我们使用的信号呢?看一下源码就知道啦。

Q_SIGNALS:
    void started(QPrivateSignal);
    void finished(QPrivateSignal);

我们来看看 QThread 是不是真的支持这两个信号。

#include <QApplication>
#include <QObject>
#include <QDebug>
#include <QThread>

class ThreadTest : public QThread
{
public:
    ThreadTest() {}

    void run()
    {
        msleep(2000);
    }
};


class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr){}

public slots:
    void getstarted()
    {
        qDebug()<<objectName()<<":"<<"getstarted()";
    }
    void getfinished()
    {
        qDebug()<<objectName()<<":"<<"getfinished()";
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    ThreadTest threada;
    MyClass my;

    my.setObjectName("my");

    QObject::connect(&threada,SIGNAL(started()),&my,SLOT(getstarted()));
    QObject::connect(&threada,SIGNAL(finished()),&my,SLOT(getfinished()));

    threada.start();

    return a.exec();
}

从运行结果上看确实收到了这两个信号呢。
在这里插入图片描述
在工程开发中,我们可以利用这两个信号来知道线程是什么时候开启和结束的。


QThread 已经定好了一些供我们使用的方便的信号,现在我们来试一试自定义信号和槽。

我们在刚才的代码上稍加修改

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr){}

public slots:
    void getstarted()
    {
        qDebug()<<objectName()<<":"<<"getstarted()";
    }

    void getfinished()
    {
        qDebug()<<objectName()<<":"<<"getfinished()";
    }
signals:
};


class ThreadTest : public QThread
{
    Q_OBJECT
public:
    ThreadTest()
    {
        connect(this,SIGNAL(counter(int)),this,SLOT(getCounter(int)));
        connect(this,SIGNAL(counter_reset()),this,SLOT(on_counter_reset()));
    }

    void run()
    {

        int m_counter = 0;
        for(int i = 0;i<10;i++)
        {
            if(0==i%5)
            {
                m_counter = 0;
                emit counter_reset();
            }

            emit counter(m_counter);
            m_counter = m_counter + 1;
            msleep(200);
        }
    }
signals:
    void counter(int n);
    void counter_reset();

public slots:
    void getCounter(int n)
    {
        qDebug()<< "getCounter : "<<n;
    }
    void on_counter_reset()
    {
        qDebug()<< "counter reset now !";
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    ThreadTest threada;
    MyClass my;

    my.setObjectName("my");

    QObject::connect(&threada,SIGNAL(started()),&my,SLOT(getstarted()));
    QObject::connect(&threada,SIGNAL(finished()),&my,SLOT(getfinished()));

    threada.start();

    return a.exec();
}

运行结果
在这里插入图片描述


我们应该要知道

  • 进程中存在栈空间的概念
  • 这个栈空间是专门用于函数调用的(比如保存函数参数,局部变量等)
  • 线程拥有独立的栈空间(可以利用这个栈空间调用其他函数)

如果一个函数的函数体中没有访问临界资源的代码,那么这个函数可以被多个线程同时调用,不会产生任何副作用。因为线程调用函数的时候用的是自己的栈空间,既然线程的栈空间是独立的,那么谁调用函数就用谁的栈空间,互不干扰。

所以问题来了,槽函数本质也是个函数,那么槽函数是谁调用的啊???是主线程还是定义槽函数的线程还是其他线程???

一般来说,我们开启一个线程,那么这个线程应该会有自己的线程 id。为了知道当前线程的 id ,我们先看看QThread有没有提供方便我们使用的方法。

从 QThread 的类定义中我们可以找到这个玩意

static Qt::HANDLE currentThreadId() Q_DECL_NOTHROW Q_DECL_PURE_FUNCTION;

那我们就试一试呗,看看是哪个线程调用槽函数。

#include <QApplication>
#include <QObject>
#include <QDebug>
#include <QThread>

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr){}

public slots:
    void getstarted()
    {
        qDebug()<<objectName()<<":"<<"getstarted() , tid :"<<QThread::currentThreadId();
    }

    void getfinished()
    {
        qDebug()<<objectName()<<":"<<"getfinished(), tid :"<<QThread::currentThreadId();
    }

signals:
};

class ThreadTest : public QThread
{
    Q_OBJECT
public:
    ThreadTest()
    {
        connect(this,SIGNAL(counter(int)),this,SLOT(getCounter(int)));
        connect(this,SIGNAL(counter_reset()),this,SLOT(on_counter_reset()));
    }

    void run()
    {
        qDebug()<<"ThreadTest tid"<<currentThreadId();
        int m_counter = 0;
        for(int i = 0;i<10;i++)
        {
            if(0==i%5)
            {
                m_counter = 0;
                emit counter_reset();
            }

            emit counter(m_counter);
            m_counter = m_counter + 1;
            msleep(200);
        }
    }
signals:
    void counter(int n);
    void counter_reset();

public slots:
    void getCounter(int n)
    {
        qDebug()<< "tid:"<<currentThreadId()<< " , getCounter : "<<n;
    }
    void on_counter_reset()
    {
        qDebug()<< "tid:"<<currentThreadId()<< "counter reset now !";
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    qDebug()<<"main tid:"<< QThread::currentThreadId();

    ThreadTest threada;
    MyClass my;

    my.setObjectName("my");

    QObject::connect(&threada,SIGNAL(started()),&my,SLOT(getstarted()));
    QObject::connect(&threada,SIGNAL(finished()),&my,SLOT(getfinished()));

    threada.start();

    return a.exec();
}

运行结果
在这里插入图片描述
从运行结果看,我们的槽函数好像并不是在我们开启的线程中调用的呢,而是在主线程中。

可是我们槽函数在线程类中写的,却跑到主线程中调用了,大家不觉得奇怪吗。这样难道不会出现什么奇怪的 bug 吗?是 QT 不完善?还是别的原因?


QT 多线程信号与槽(二)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT 多线程信号与槽(一) 的相关文章

随机推荐

  • 基于深度学习的高精度课堂人脸检测系统(PyTorch+Pyside6+YOLOv5模型)

    摘要 基于深度学习的高精度课堂人脸检测系统可用于日常生活中或野外来检测与定位课堂人脸目标 利用深度学习算法可实现图片 视频 摄像头等方式的课堂人脸目标检测识别 另外支持结果可视化与图片或视频检测结果的导出 本系统采用YOLOv5目标检测模型
  • 1084. 销售分析III(SQL)

    题目 https leetcode cn com problems sales analysis iii Table Product Column Name Type product id int product name varchar
  • demo演示是什么意思_路演(融资演示)时要注意些什么?

    路演 融资演示 究竟重不重要 如果你的企业足够优秀 那可能路演对你来说就没那么重要 甚至都不需要路演 可能就有很多投资人抢着来投你 但能达到这个水平的毕竟是少数 更多的是默默无闻的创业者 如果你的企业还没有那么优秀 或者你的产品还不够成熟
  • Python_捕获未知错误代码

    try num int input 请输入一个整数 result 8 num print result except Exception as result print 未知错误 s result
  • VScode编译调试C++环境

    首先去官网下载vscodehttps code visualstudio com 为了编译C C 要使用gcc Windows本身不支持gcc 所以有了MinGW 我用的是dev带的MinGW 也可以自己安装MinGW 或者用VS的编译器
  • VTM7.0配置并运行(windows系统)

    文章目录 一 下载安装VTM 下载方式一 下载方式二 1 解压VTM软件压缩包 2 在解压好的目录里新建 build 文件夹 二 下载安装Cmake 1 下载Cmake并解压 2 配置Cmake环境变量 三 编译 方法一 界面 1 打开 c
  • Netty案例(二)之耗时任务的处理

    文章目录 netty版本 Netty耗时任务的处理 代码案例 Handler 自定义业务线程池 Context中添加线程池 netty版本 使用的netty版本是io netty netty all 4 1 33 Final Netty耗时
  • 全网最好的免费开源ERP:Odoo库存路线规则设置应用详解

    引言 在库存管理中 供应链战略确定了产品何时应该采购或制造 交付到分销中心 并最终提供给零售渠道 在开源智造 Odoo免费开源ERP解决方案中 可以使用WMS应用中的仓库路线来配置产品的供应链策略 其中包括库内作业的拉取和推送规则 一旦一切
  • Java架构直通车——深入理解B+树

    文章目录 引入 AVL树和B树 AVL树 红黑树 B树 B 树 数据库为什么不使用二叉树 为什么使用B 树 与B树的区别 引入 AVL树和B树 AVL树 平衡二叉搜索树是基于二分法的策略提高数据的查找速度的二叉树的数据结构 平衡二叉搜索树的
  • 删除双系统中的一个linux,双系统删除linux

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 双系统删除linux系统2008 10 12 00 27方法一 我们知道在xp里一个很好的分区工具 PQ partition magic 但在双系统下 由于linux改变了xp里C盘的一个启动项
  • LVGL-obj对象

    对象创建 1 lv中所有的对象都以obj为基础进行扩展的 创建对象时父对象是空 则在显示器屏链表增加一个节点 父对象非空则在其子链表增加一个节点 创建完成会通过parent gt signal cb parent LV SIGNAL CHI
  • MySQL数据库之索引

    目录 前言 一 索引的概念 二 索引的作用和副作用 1 索引的作用 2 索引的副作用 3 创建索引的原则依据 总结 三 索引的分类和创建 1 普通索引 1 直接创建索引 2 修改表方式创建 3 创建表的时候指定索引 不建议 2 唯一索引 1
  • 国标GB28181安防视频平台EasyGBS显示状态正常,却无法播放该如何解决?

    国标GB28181视频平台EasyGBS是基于国标GB T28181协议的行业内安防视频流媒体能力平台 可实现的视频功能包括 实时监控直播 录像 检索与回看 语音对讲 云存储 告警 平台级联等功能 国标GB28181视频监控平台部署简单 可
  • C/C++函数参数读取顺序

    说到C C 函数参数读取顺序 很多人都知道在入栈时是从右至左的 可是真的有那么简单吗 先看一个例子 include
  • 允许chatgpt上传文件的插件

    https chrome google com webstore detail chatgpt file uploader ext becfinhbfclcgokjlobojlnldbfillpf related 事实上在其它浏览器 例如e
  • Solidity编程开发实例

    Solidity 编程开发实例 Voting 投票 接下来的智能合约教程非常复杂 但展示了很多Solidity的特性 它实现了一个入门的投票合约 当然 电子选举的主要问题是如何赋予投票权给准确的人 并防止操纵 我们不能解决所有的问题 但至少
  • java-编程输出一个随机字母

    编程输出一个随机字母 public class s public static void main String args TODO Auto generated method stub int i int Math random 2 1
  • Sqlite学习笔记(四)&&SQLite-WAL原理 Write ahead logging

    Sqlite学习笔记 四 SQLite WAL原理 转 2015 08 24 21 55 by 沧海一滴 90 阅读 0 评论 收藏 编辑 Sqlite学习笔记 三 WAL性能测试中列出了几种典型场景下WAL的性能数据 了解到WAL确实有性
  • linux下QT源码安装简书,QT Creator 5在linux下的安装及问题(libCore.so无法加载)的解决...

    Qt 以其开源 免费 完全面向对象 很容易扩展 允许真正的组件编程以及可移植跨平台等诸多优势得到越来越多的开发人员的青睐 Qt Creator 是 Nokia 官方推出的专门针对 Qt 开发的 IDE 本文详细介绍了 Linux 下 Qt
  • QT 多线程信号与槽(一)

    QT 中 QObject 作QT中类的最终父类 具有自定义信号与槽的能力 只要继承自这个类的类 也一样拥有自定义信号和槽的能力 QT 中定义信号与槽是十分有用的 那我们的线程类是不是也有这个能力呢 查一下 QThread 的源码 我们发现