Qt implements two ways of multithreading: rewrite run() and moveToThread(), connect the fifth parameter description

Rewrite run(): define a thread class, inherit from QThread, rewrite virtual function run(), the code in run is executed in the child thread;
moveToThread(): define a thread class, inherit from QObject, in the main thread instance An object of this class is instantiated and an object of the QThread class is instantiated. The former is moveToThread and the latter is multi-threaded through signal slots. Multiple signal slots can be defined. Slot functions are all running in the same child thread. You can use connect The fifth parameter controls whether the slot function runs in a sub-thread (the default is multi-threaded under multi-threading, and the queue is multi-threaded, directly running the slot in the main thread).

Rewrite the virtual function run() of QThread

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
//头文件和基类由QObject改成QThread
class MyThread : public QThread
{
    
    
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);
protected:
    //QThread的虚函数
    //线程处理函数
    //不能直接调用,通过start()间接调用
    void run();
signals:
    void isDone();
public slots:
};
#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
//基类改成QThread
MyThread::MyT hread(QObject *parent) : QThread(parent)
{
    
    
}
void MyThread::run()
{
    
    
    //非常复杂的数据处理
    //耗时5s
    sleep(5);

    emit isDone();
}

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif

#include <QWidget>
#include<QTimer>//定时器头文件
#include"mythread.h"//线程头文件
namespace Ui {
    
    
class MyWidget;
}
class MyWidget : public QWidget
{
    
    
    Q_OBJECT
public:
    explicit MyWidget(QWidget *parent = nullptr);
    ~MyWidget();

    void dealTimerout();//定时器槽函数
    void dealDone();//线程结束槽函数
    void stopThread();//停止线程槽函数
private slots:
    void on_pushButton_clicked();
private:
    Ui::MyWidget *ui;
    QTimer *myTimer;//声明变量
    MyThread *thread;//线程对象
};
#endif // MYWIDGET_H

mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include<QThread>
#include<QDebug>

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    
    
    ui->setupUi(this);

    myTimer = new QTimer(this);

    //只要定时器启动,自动触发timeout()槽函数
    connect(myTimer,&QTimer::timeout,this,&MyWidget::dealTimerout);

    thread = new MyThread(this);

    connect(thread,&MyThread::isDone,this,&MyWidget::dealDone);

    //当按窗口右上角关闭时,窗口触发destroy()信号
    connect(this,&MyWidget::destroyed,this,&MyWidget::stopThread);
}
//停止线程
void MyWidget::stopThread()
{
    
    
    //停止线程
    thread->quit();
    //等待线程处理完手头工作
    thread->wait();
}

void MyWidget::dealDone()
{
    
    
    qDebug() << "it is over";
    myTimer->stop();//关闭定时器
}

void MyWidget::dealTimerout()
{
    
    
    static int i = 0;
    i++;
    ui->lcdNumber->display(i);
}

MyWidget::~MyWidget()
{
    
    
    delete ui;
}
//启动线程
void MyWidget::on_pushButton_clicked()
{
    
    
    //如果定时器没有工作,点start才进入
    if(myTimer->isActive() == false)
    {
    
    
        myTimer->start(100);
    }
    //启动线程,处理数据
    thread->start();
}

moveToThread()

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif
#include <QObject>
class MyThread : public QObject
{
    
    
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);
    //线程处理函数
    void myTimeout();
    void setFlag(bool flag = true);
signals:
    void mySignal();
private:
    bool isStop;
public slots:
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include<QThread>
#include<QDebug>

MyThread::MyThread(QObject *parent) : QObject(parent)
{
    
    
    isStop = false;
}
//线程处理函数
void MyThread::myTimeout()
{
    
    
    while(isStop == false)
    {
    
    
        //每隔1s发射一个信号
        QThread::sleep(1);
        emit mySignal();
        //打印子线程号
        qDebug() << "子线程号:" << QThread::currentThread();
        if(isStop == true)
            break;
    }
}

void MyThread::setFlag(bool flag)
{
    
    
    isStop = flag;
}

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif

#include <QWidget>
#include"mythread.h"
#include<QThread>

namespace Ui {
    
    
class MyWidget;
}
class MyWidget : public QWidget
{
    
    
    Q_OBJECT
public:
    explicit MyWidget(QWidget *parent = nullptr);
    ~MyWidget();
    void dealSignal();
    void dealClose();
signals:
    void startThread();//启动子线程的信号
private slots:
    void on_buttonStart_clicked();
    void on_buttonStop_clicked();
private:
    Ui::MyWidget *ui;

    MyThread *myT;
    QThread *thread;
};

#endif // MYWIDGET_H

mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include<QDebug>

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    
    
    ui->setupUi(this);
    //动态分配空间,不能指定父对象,因为下一步要加入到子线程
    myT = new MyThread;

    //创建子线程,可以指定父对象
    thread = new QThread(this);

    //把自定义的线程加入到子线程中
    myT->moveToThread(thread);

    connect(myT,&MyThread::mySignal,this,&MyWidget::dealSignal);

    //打印主线程号
    qDebug() << "主线程号:" << QThread::currentThread();

    connect(this,&MyWidget::startThread,myT,&MyThread::myTimeout);
    //右上角x关闭窗口时,关闭线程
    connect(this,&MyWidget::destroyed,this,&MyWidget::dealClose);
    //线程处理函数内部,不允许操作图形界面

    //connect()第五个参数的作用,连接方式:默认、队列、直接
    //第五个参数多线程时才有意义
    //默认的时候
    //如果是多线程,默认使用队列
    //如果是单线程,默认使用直接方式
    //队列:槽函数所在线程和接收者一样
    //直接:槽函数所在线程和发送者一样
    //一般选用默认,程序会自动判断单线程还是多线程
}

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

void MyWidget::dealClose()
{
    
    
//    myT->setFlag(true);
//    thread->quit();
//    thread->wait();

    //或者直接调用槽函数
    on_buttonStop_clicked();

    //myT未指定父对象,关闭时释放内存
    delete myT;
}

void MyWidget::dealSignal()
{
    
    
    static int i = 0;
    i++;
    ui->lcdNumber->display(i);
}

void MyWidget::on_buttonStart_clicked()
{
    
    
    //做个判断,线程已启动就不进入
    if(thread->isRunning() == true)
        return;

    //启动线程,但是没有启动线程处理函数
    thread->start();
    myT->setFlag(false);

    //不能直接调用线程处理函数
    //直接调用会导致,线程处理函数和主线程是在同一个线程
    //myT->myTimeout(); //运行异常,主线程和子线程号一样

    //只能通过 signal - slot 方式调用(信号与槽)
    emit startThread();
}

void MyWidget::on_buttonStop_clicked()
{
    
    
    //做个判断,线程已关闭,不进行退出操作
    if(thread->isRunning() == false)
    {
    
    
        return;
    }

    //按下stop,Flag变为true
    myT->setFlag(true);
    thread->quit();
    thread->wait();
}

connect fifth parameter

Qt::AutoConnection, the default value, use this value to determine the connection type when the signal is sent. If the receiver and sender are in the same thread, the Qt::DirectConnection type is automatically used. If the receiver and sender are not in the same thread, the Qt::QueuedConnection type is automatically used.
Qt::DirectConnection, the slot function will be called directly when the signal is sent, and the slot function runs on the thread where the signal is sent. The effect looks like the slot function is called directly at the signal sending position. This is more dangerous in a multi-threaded environment and may cause crashes.
Qt::QueuedConnection, the slot function is called when control returns to the event loop of the thread where the receiver is located, and the slot function runs on the thread where the signal receiver is located. After the signal is sent, the slot function will not be called immediately. The slot function will not be called until the receiver's current function is executed and enters the event loop. This is generally used in a multi-threaded environment.
Qt::BlockingQueuedConnection, the calling timing of the slot function is the same as Qt::QueuedConnection, but the thread of the sender will block after sending the signal until the slot function is finished. The receiver and sender must not be in the same thread, otherwise the program will deadlock. This may be needed when synchronization between multiple threads is required.
Qt::UniqueConnection, this flag can be combined with the above four by bitwise OR (|). When this flag is set, when a signal and slot are already connected, repeated connections will fail. That is, repeated connections are avoided.
Disconnect method: Although this method is not necessary, when an object is deleted, Qt automatically cancels all slots connected to the object.
disconnect(sender,SIGNAL(signal),receiver,SLOT(slot),Qt::DirectConnection);

Guess you like

Origin blog.csdn.net/weixin_40355471/article/details/110393257