12.QT线程的两种启动方式

一、QT中的线程

QT中的线程主要是通过QThread进行管理,一个QThread对象管理程序中的一个线程。 QThreads管理的线程在run()中开始执行。 默认情况下,run()通过调用exec()启动并在线程中运行事件循环。

线程的启动方式有两种:

1.使用moveToThread启动线程

示例

//头文件
#ifndef THREADSTART_H
#define THREADSTART_H

#include <QObject>
#include <QThread>
#include <iostream>
#include <cassert>

using namespace std;

class work : public QObject
{
    Q_OBJECT
public:
    explicit work(QObject *parent = nullptr);
    virtual ~work();

public slots:
    void dowork();

signals:
    void emitsignal();
};

class control:public QObject
{
    Q_OBJECT
public:
    explicit control(QObject *parent=nullptr);
    virtual ~control();

public slots:
    void signalhandler();

signals:
    void worksignal();

private:
    QThread workthread_;
};

#endif // THREADSTART_H
//源文件
#include "threadstart.h"

work::work(QObject *parent) : QObject(parent)
{
    cout<<__func__<<endl;
}

work::~work()
{
    cout<<__func__<<endl;
}

void work::dowork()
{
    while(1) {
        QThread::sleep(1);
        cout<<__func__<<QThread::currentThreadId()<<endl;
        emit emitsignal();
    }
}

control::control(QObject *parent):QObject(parent)
{
    work *pwork=new work();
    pwork->moveToThread(&workthread_);//将pwork指向的对象移动到目标线程workthread_中
    connect(&workthread_, &QThread::finished, pwork, &QObject::deleteLater);
    connect(this, &control::worksignal, pwork, &work::dowork);
    connect(pwork, &work::emitsignal, this, &control::signalhandler);

    workthread_.start();//start内部会调用run函数启动一个线程,如果不重新run函数,run函数默认执行exec

    emit worksignal();
}

control::~control()
{
    cout<<__func__<<endl;
    workthread_.quit();
    workthread_.wait();
}

void control::signalhandler()
{
    cout<<__func__<<QThread::currentThreadId()<<endl;
    cout<<"received signal"<<endl;
}
//主函数
#include <QCoreApplication>
#include "threadstart.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    cout<<QThread::currentThreadId()<<endl;
    control cl;
    return a.exec();
}

上述程序输出结果如下

上述代码的思路就是在主线程中创建一个QThread对象,然后将工作函数放在该QThread对象对象中去执行,当主线程发出worksignal时,会调用工作线程中的槽函数,在工作线程的槽函数中,又会发射新的信号emitsignal,最后回到主线程中调用槽函数

 

2.继承QThread

示例

//头文件
#ifndef THREADSTART2_H
#define THREADSTART2_H

#include <QObject>
#include <QThread>
#include <iostream>
#include <cassert>

using namespace std;

class threadstart2 : public QObject
{
    Q_OBJECT
public:
    explicit threadstart2(QObject *parent = nullptr);
    virtual ~threadstart2();
public slots:
    void handlesignals();
};

class workthread:public QThread
{
    Q_OBJECT
public:
    workthread();
    virtual ~workthread();
protected:
    void run() override;

signals:
    void emitsignal();
};

#endif // THREADSTART2_H
//源文件
#include "threadstart2.h"

threadstart2::threadstart2(QObject *parent) : QObject(parent)
{
    workthread *wt=new workthread();
    connect(wt, &workthread::emitsignal, this, &threadstart2::handlesignals);
    wt->start();
}

threadstart2::~threadstart2()
{
    cout<<__func__<<endl;
}

void threadstart2::handlesignals()
{
    cout<<__func__<<endl;
}

workthread::workthread() : QThread()
{
    cout<<__func__<<endl;
}

workthread::~workthread()
{
    cout<<__func__<<endl;
}

void workthread::run()
{
    while(1) {
        QThread::sleep(1);
        emit emitsignal();
        cout<<QThread::currentThreadId()<<endl;
    }
}
//主函数
#include <QCoreApplication>
#include "threadstart2.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    cout<<QThread::currentThreadId()<<endl;
    threadstart2 ts2;
    return a.exec();
}

示例代码的思路就是定义一个继承QThread的类并重写run函数,然后在主线程中实例化该类并启动线程,最后执行run函数并发出信号

这种线程的启动方式和第一种方式有一个区别,就是信号对应的槽函数在主线程中执行而不在新线程中执行

原因是因为:一个QThread实例位于实例化它的旧线程中,而不位于调用run函数的新线程中。 所以,所有QThread排队执行的槽函数也都将在旧线程中执行。

因此,如果想在新线程中调用槽函数,请使用第一种方式启动QT的线程。 

 

参考

https://doc.qt.io/qt-5/qthread.html#details

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值