论QT6多线程技术

前言

以前我多线程使用传统的继承qthread重写run()或者继承qrunable类把对象丢到线程池解决。经过昨天的面试让我了解到新的技术,我之前看到过只不过没有详细的去了解movetotread技术,这个技术是qt5推出的,qt6还在延续使用

代码结构

以下是简单的movetotread的实现

class Worker:public QObject{
Q_OBJECT
private slots:
dowork();/*业务逻辑*/
}

//使用方式
QThread thread;
Worker woker;
woker.movetotread(&tread);
thread.start();
//通过信号触发work
QObject::connect(&sender,&sender::startsignal,&worker,&worker::doworke);

实现逻辑

movetotread实现了线程与事务相分离,但需要运行某个事件的时候只需要将继承了QObject类的对象通过movetotread(&目标线程)传进去执行,通过qdequeueconnect()实现跨线程通讯。

关键操作

初次创建线程的时候通过start()函数,它会调用run()函数并启动事件循环(默认exec())

退出线程有三种

thread->quit();//优雅退出
tread->wait();//主线程阻塞等待子线程结束
thread->terminate();//强制退出线程,不推荐这种,可能导致线程未释放

创建好线程以后可以写两个connect管理对象和线程当线程执行完时释放finished信号来管理对象和线程的生命周期

connect(thread,&qthread::finished,worker,&QObject::deletelater);
connect(thread,&qthread::finished,thread,&QObject::deletelater);

跨线程的时候不要直接调用对象内的方法,可以通过主线程connect信号触发worker->doworker();

其他注意细节

如果线程未被释放,是可以通过movetothread将新的对象传进去。

如果向一个线程里面重复movetothread,最新的对象会把上一个对象给替代掉。

小实验

我设计两个线程,一个是主线程,里面是mainwindow,一个是子线程,专门生产1-6的随机数,生产好了以后将生成的数字传递到主线程显示出来

首先是建一个随机数生成器类randomnum

//头文件
#ifndef RANDOMNUM_H
#define RANDOMNUM_H
#include<QObject>
#include<QRandomGenerator>
#include<QTimer>

class randomnum : public QObject
{
    Q_OBJECT
public:
    explicit randomnum(QObject *parent = nullptr);
public slots:
    void startrandom();//开始生成随机数
    void stoprandom();//暂停生成
signals:
    void newnumber(int count,int number);
private:
    QTimer *timer;//计时器
    int count=0;//计数
    QRandomGenerator random;//随机数生成器
};

#endif // RANDOMNUM_H
//cpp
#include "randomnum.h"
#include "qobject.h"

randomnum::randomnum(QObject *parent)
    : QObject{parent}
{
    timer=new QTimer(this);
    connect(timer,&QTimer::timeout,this,[this](){
        count++;
        int num=random.bounded(1,6);
        emit newnumber(count,num);
    });
}

void randomnum::startrandom()
{
    timer->start(1000);
}

void randomnum::stoprandom()
{
    timer->stop();
}

主程序

//头文件
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QThread *thread1;

private slots:
    void appendnum(int count,int num);

};
#endif // MAINWINDOW_H
//cpp文件
#include "randomnum.h"
#include "ui_mainwindow.h"
#include<QString>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->plainTextEdit->setReadOnly(true);

    //创建工作对象和线程
    randomnum *random1=new randomnum;
    thread1=new QThread(this);

    //把工作对象移动到子线程
    random1->moveToThread(thread1);

    //连接信号槽
    //触发开始随机数的信号
    //connect(thread1,&QThread::started,random1,&randomnum::startrandom);
    //把子线程生成的信号参数传给主线程对应的槽函数
    connect(random1,&randomnum::newnumber,this,&MainWindow::appendnum);
    //开始按钮
    connect(ui->btnstart,&QPushButton::clicked,random1,&randomnum::startrandom);
    //暂停按钮
    connect(ui->btnstop,&QPushButton::clicked,random1,&randomnum::stoprandom);

    //管理对象生命周期
    connect(thread1,&QThread::finished,random1,&QObject::deleteLater);
    //connect(thread1,&QThread::finished,thread1,&QObject::deleteLater);

    thread1->start();
}

MainWindow::~MainWindow()
{
    if(thread1&&thread1->isRunning()){
        thread1->quit();
        thread1->wait();
    }
    delete ui;
}

void MainWindow::appendnum(int count, int num)
{
    QString str=QString("第%1次,数字是%2").arg(count).arg(num);
    ui->plainTextEdit->appendPlainText(str);
}

显示效果

程序怎么实现的看上面代码就行了,这里讲下遇到的问题:

1.关闭程序,程序崩溃,子线程没有停止导致的,刚开始的时候明明有一个connect连接finished的信号,结果还是没关掉,原因是deletlater只是标记了他为待删除,不需要这一句,直接在析构函数里面显示删除,之前那一句不要了,避免重复删除

2.添加开始/停止按钮,用这个直接操作计时器,不是操控线程就可以实现 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值