Qt中的多线程编程(2)

本文介绍了在Qt中除了继承QThread并重写run()函数的经典方法外,如何利用QThread的exec()事件循环和信号槽机制来创建线程。这种方法更符合逻辑,通过定义QThread对象,链接start()信号到槽函数,将对象移动到新线程中。文章通过示例代码展示了具体实现步骤,并得出结论,推荐使用这种新的线程创建方式。
摘要由CSDN通过智能技术生成

Qt中另一种创建线程的方法

上一篇博客中,我介绍了一种Qt中经典的的创建线程的方法:继承QThread类、子类中重写run()函数的方法。经典方法虽然使用简单,但是有一个问题:在合理的软件架构中,代码中出现的继承关系,也应该真实反应需求中继承关系,思考一下:通过继承的方式实现新的线程类,有什么实际的意义?我觉得完全没有实际的意义,仅仅是为了重写run()函数。但是虽然没有实际意义,但是也不能说它是错误的,只不过在逻辑上有点背离面向对象。

下面开始介绍新的创建线程的方法

首先,我们得知道Qt4.4版本之前,QThread::run()是纯虚函数:virtual void run() = 0;QThread::run()仅仅是个声明,没有任何属性,子类是必须完全重写run()的,这个时候我们也只有这一种创建多线程的方法。但是在Qt4.4版本之后,Qt对QThread::run()做了修改:

virtual void run() 
{
    exec(); 
}

run()函数就默认调用了exec()事件循环,使得这第二种创建线程的方法得以实现:使用信号与槽机制,将一个槽函数作为线程的入口函数。方法是这个方法,具体实现的步骤,按照我的经验总结一些:

  1. 在当前类中定义一个private QThread类对象
  2. 在当前类中定义一个private 的槽函数,这个槽是作为线程入口函数,所有需要在新线程中实现的操作,都在这里编写。
  3. 当然就是链接信号与槽了。线程的start()的信号链接到这个槽函数。
  4. 将当前对象moveToThread到定义的线程对象。
    下面是示例代码:
//以下是main.cpp
#include <QCoreApplication>
#include "QDebug"
#include "testcl.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug()<<"main threadID :"<<QThread::currentThreadId()<<endl;//打印主线程ID
    //
    testCl cl;
    cl.threadStart();
    cl.threadTerminate();
    return a.exec();
}
//以上是main.cpp

//以下是testcl.h
#ifndef TESTCL_H
#define TESTCL_H
#include <QObject>
#include "QThread"
#include "QDebug"
class testCl : public QObject
{
    Q_OBJECT
public:
    explicit testCl(QObject *parent = nullptr);
    void threadStart();
    void threadTerminate();
private:
    QThread newThread;//定义一个QThread对象,事实上,QThread类中实现了
    //系统层面的线程函数
private slots:
    void slotThread();
signals:
};
#endif // TESTCL_H
//以上是testcl.h
//以下是testcl.cpp
#include "testcl.h"
testCl::testCl(QObject *parent) : QObject(parent)
{
    connect( &newThread,SIGNAL(started()),this,SLOT(slotThread()));
    moveToThread(&newThread);
}
void testCl::threadStart()
{
    newThread.start();
    qDebug()<<"threadStart ID :"<<thread()->currentThreadId()<<endl;//打印这个对象的普通函数的线程ID
}
void testCl::threadTerminate()
{
    newThread.terminate();
    qDebug()<<"threadTerminate ID :"<<thread()->currentThreadId()<<endl;//打印这个对象的普通函数的线程ID
}
void testCl::slotThread()
{
    qDebug()<<"slotThread ID :"<<thread()->currentThreadId()<<endl;//打印这个对象的线程槽函数的ID
}
//以上是testcl.cpp

以上代码是使用新的方法创建了线程,分别要打印主线程ID,两个类中普通成员函数所在的线程ID、连接到新线程的槽函数的线程ID,按照我们的理解,我们在main()函数中定义了testcl对象,那么testcl所有普通成员变量和成员函数都应该与main()函数线程保持一致,而槽函数是作为新线程入口函数的,线程ID号肯定与main()函数不一样。
运行一下,看看结果是否如我们所想:
在这里插入图片描述运行结果如我们所想。这也证明了新的线程创建方法是有效的,综合整个过程,我们能够得到如下结论:

  • Qt中经典的线程创建方法,是基于继承QThread再重写入口函数的方法,属于类与类继承的方式;但是今天介绍的方法,是属于类与类组合的方式,在线程创建这一点上,显然是组合的方式更符合逻辑。
  • 这个创建线程方式能够实现,得益于QThread::run()中默认调用exec();线程启动后,先是执行run()函数中exec(),进入了事件循环,信号与槽机制生效,这个时候发出的started()信号才能进入槽。
  • Qt官方推荐使用今天的新方式进行线程创建。

原创内容,禁止转载

王雄 第一次更新于2021.03.07

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值