qt中实现多线程的2种方式

2023年8月9日 14:00 ry 340

之前在写相机的一个项目,需要按照帧率实现多线程采集,我们用qt来实现下,首先第一种方式,直接继承OThread来创建自定义的线程类,我们用QTcreator来创建一个项目,这个项目我们准备实现一个计数的效果,窗口实时显示,我们先在ui中拖拽设置下界面,如图所示,这是我设置的界面首先设置一个终点数,比如1000,点击开始然后界面显示从0-1000,如果这个不用子线程,直接在主线程中实现毫无意外程序会崩溃无响应,要么无法实时看到数字显示的效果,要么直接被迫关闭。在qt中主线程也叫gui线程,包括对一些页面用户事件进行处理,由qt自带的,因此我们随便创建一个qt项目,都有主线程,可以很方便地让用户实现界面操作和管理。而对于一些耗时的需要计算的任务,用主线程处理就会导致阻塞了,造成页面无法响应直至强制退出的结果,因此对于一些耗时操作,需要子线程来实现。简单地来说,子线程处理逻辑事务,主线程处理界面ui事务。像对于我们的这个功能,界面实时显示数字这个操作是交给主线程来实现的,而里面的一些逻辑事务,像实现从0-1000循环的操作是通过子线程来实现的,那么这就很好办了,先子线程实现,并将实现的结果传给主线程显示即可。接下来我们通过继承QThread来实现多线程,新建文件,如图所示由于我们要继承QThread的,而这个没有这个选项,我们选择QObject即可,后面我么在代码中手动更改回来即可。设置类名Mythread,记得大写,然后点击下一步,下一步即可,然后目录就多了mythread.h,mythread.cpp文件。然后在mythread.h中更改,代码如下

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

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

signals:

public slots:
};

#endif // MYTHREAD_H

mythread.cpp代码如下

#include "mythread.h"

Mythread::Mythread(QObject *parent) : QThread(parent)
{

}

由于线程的逻辑都通过run方法实现执行的,我们得实现run方法(重写),完整代码,mythread.h文件代码

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class Mythread : public QThread
{
    Q_OBJECT
public:
    explicit Mythread(QObject *parent = nullptr);
    virtual void run() override;

signals:
    void send(int num);

public slots:
};

#endif // MYTHREAD_H

mythread.cpp文件代码

#include "mythread.h"
#include<QDebug>
Mythread::Mythread(QObject *parent) : QThread(parent)
{

}

void Mythread::run()
{
    for(int i=0;i<1000000;i++)
    {
        emit send(i);
        qDebug()<<i;
    }
}

widget.h代码

#ifndef WIDGET_H
#define WIDGET_H
#include<mythread.h>
#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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


public slots:
    void showMsg(int num);
    //点击开始启动线程
    void on_btn_start_clicked();

private:
    Ui::Widget *ui;
    Mythread *mythread = nullptr;
};
#endif // WIDGET_H

widget.cpp代码

#include "widget.h"
#include "ui_widget.h"
#include<mythread.h>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    mythread = new Mythread();
    //接收子线程传来的数据
    connect(mythread,SIGNAL(send(int)),this,SLOT(showMsg(int)));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::showMsg(int num)
{
    ui->label_show->setText(QString::number(num));
}

void Widget::on_btn_start_clicked()
{
    mythread->start();
}

完美实现,整个过程很容易,通过信号和槽来启动子线程,子线程传来数据到主线程显示即可,这是直接继承QThread实现的多线程,接下来我们换另一种方法,即间接继承QThread实现多线程,这个更加灵活。上面的我们直接继承QThread的是将QObject改成了QThread,而间接继承的则不用这样更改了,mythread.h的完整代码如下所示

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>

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



signals:
    void send(int num);

public slots:
    void working();
};

#endif // MYTHREAD_H

mythread.cpp的完整代码如下所示

#include "mythread.h"
#include<QDebug>
Mythread::Mythread(QObject *parent) : QObject(parent)
{

}

void Mythread::working()
{
    for(int i=0;i<1000000;i++)
    {
        emit send(i);
        qDebug()<<i;
    }
}


widget.h的完整代码如下所示

#ifndef WIDGET_H
#define WIDGET_H
#include<mythread.h>
#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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


public slots:
    void showMsg(int num);
    //点击开始启动线程
    void on_btn_start_clicked();

private:
    Ui::Widget *ui;
    Mythread *mythread = nullptr;
    QThread *t = nullptr;
signals:
    void begin();
};
#endif // WIDGET_H

widget.cpp的完整代码如下所示

#include "widget.h"
#include "ui_widget.h"
#include<mythread.h>
#include<QThread>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    mythread = new Mythread();
    t = new QThread();
    mythread->moveToThread(t);
    connect(this,&Widget::begin,mythread,&Mythread::working);
    //接收子线程传来的数据
    connect(mythread,SIGNAL(send(int)),this,SLOT(showMsg(int)));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::showMsg(int num)
{
    ui->label_show->setText(QString::number(num));
}

void Widget::on_btn_start_clicked()
{
    emit begin();
    t->start();
}

实现效果一样,完美,现在来说下二者的不同,间接继承QThread的方法子线程实现逻辑的函数名可以自定义,而直接继承QThread的方法固定run,并且只能重写,间接继承QThread的方法线程函数可以带有参数,十分方便的可以通过主线程传递,而直接继承的线程run函数不能带有参数,主线程要想给子线程传递参数必须通过内部成员变量进行传递,有点麻烦,无法灵活使用。

如果上述代码帮助您很多,可以打赏下以减少服务器的开支吗,万分感谢!

欢迎发表评论~

点击此处登录后即可评论


评论列表
暂时还没有任何评论哦...

赣ICP备2021001574号-1

赣公网安备 36092402000079号