关于使用继承QObject实现多线程的理解——Qt推荐的方法

概念

多线程的使用主要是为了处理比较耗时的过程。这可以用以下图来形象地描述:

关于使用继承QObject实现多线程的理解——Qt推荐的方法_第1张图片

目前,由于继承QObject的多线程实现方法更加灵活,Qt官方推荐使用该方法实现多线程。

想用图来描述实现的过程,发现也不好表达,将就着看吧:

关于使用继承QObject实现多线程的理解——Qt推荐的方法_第2张图片

步骤

1、创键一个继承于 QObject 的自定义线程类(如:MyThread),用来盛放比较耗时,需要放入子线程的处理函数

  • 定义一个线程处理函数(如:MyWork),当然也可以定义多个,这时多个处理函数就共用一个子线程
  • 在处理函数中进行处理,此过程可能时间较长(如:QThread::sleep(1))
  • 在处理函数中发送处理完成的信号(如:emit signal_back()),当然该信号中可能含有处理的结果信息(如计算结果) 

2、 在主线程(亦称界面线程)中创建一个子线程(QThread* subthread = new QThread(this))

3、新建一个自定义线程类对象(MyThread* m_MyThread = new MyThread())

4、将自定义线程类对象移入子线程容器中(m_MyThread->moveToThread(subthread)),其实也可以移入多个自定义线程类到同一个subthread中,这时他们就共享一个子线程了

5、连接主线程和子线程之间的信号和槽

  • 主线程——>子线程,主线程的信号和子线程的槽

connect ( this, &MainWindow::StartThread, m_MyThread, &MyThread::MyWork )

  • 子线程——>主线程,子线程的信号和主线程的槽

connect (m_MyThread, &MyThread::signal_back, this, &MainWindow::slot_handle_finish )

6、子线程使用完毕需要回收销毁,不然该线程会一直占用,而系统可分配的线程数量是有限的

subthread->qiut();      //该停止函数比较弱,会等到线程处理函数MyWork()的任务执行完之后,才会停止线程

subthread->wait();   

所有通常会加入一个标志位,来终止任务。

以上过程就实现了,从主线程进入子线程处理耗时问题,到处理完成后返回主线程的过程。

定时器线程实例

接下来看代码,有点长。。。

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include 

class MyThread : public QObject
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = 0);

    void MyWork();     //线程处理函数定义
    void setFlag(bool flag = true);

signals:
    void signal_back();//处理结果返回信号

private:
    bool isStop;
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include 
#include 

MyThread::MyThread(QObject *parent) : QObject(parent)
{
    isStop = false;
}

void MyThread::MyWork()        //线程处理函数:具体处理的事情
{
    while(!isStop)
    {
        QThread::sleep(1);
        emit signal_back();    //发送返回信号

        qDebug() << "the child thread number:" << QThread::currentThread();
    }
}

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

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include 
#include "mythread.h"
#include 

namespace Ui {
class MyWidget;
}

class MyWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MyWidget(QWidget *parent = 0);
    ~MyWidget();

    void slot_handle_finish();
signals:
    void StartThread();

private slots:
    void on_BtnStart_clicked();
    void on_BtnStop_clicked();

private:
    Ui::MyWidget *ui;
    MyThread * m_MyThread;
    QThread * subthread;
    void CloseWidget();
};

#endif // MYWIDGET_H

mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include 

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

    //creat a child thread
    subthread = new QThread(this);
    //creat a new object m_MyThread
    m_MyThread = new MyThread();
    //move the new object to child thread
    m_MyThread->moveToThread(subthread);

    connect(this, &MyWidget::StartThread, m_MyThread, &MyThread::MyWork);
    connect(m_MyThread, &MyThread::signal_back, this, &MyWidget::slot_handle_finish);

    qDebug() << "the main thread number:" << QThread::currentThread();

    connect(this, &MyWidget::destoryed, this, &MyWidget::CloseWidget);   //左上角窗口关闭
}

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

void MyWidget::on_BtnStart_clicked()
{
    if(subthread->isRunning() == true) return;
    m_MyThread->setFlag(false);

    //start the child thread    
    subthread->start();
    //启动了线程,但是并没有进入线程
    //必须通过信号/槽的方式进入子线程
    //直接通过m_MyThread->Mywork()是不行的,这样MyWork()中的线程就是主线程
    emit StartThread();
}

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

void MyWidget::on_BtnStop_clicked()
{
    if(subthread->isRunning() == true) return;
    m_MyThread->setFlag();
    subthread->quit();
    subthread->wait();
}

void MyWidget::CloseWidget()
{
    m_MyThread->setFlag();
    subthread->quit();
    subthread->wait();
    delete m_MyThread;
}

以上过程就启动线程,即通过开始按钮,开始计时

关于使用继承QObject实现多线程的理解——Qt推荐的方法_第3张图片

注:

1、子线程的处理函数中不能操作图形界面,只能进行数据处理,因为是后台运行

2、connect函数的第5个参数ConnectionType的问题

  • ConnectionType主要有三种Qt::AutoConnection(默认)、Qt::DirectConnection(直接)、Qt::QueuedConnection(队列)
  • Qt::AutoConnecdann为缺省默认参数,单线程时->Qt::DirectConnection,多线程时->Qt::QueuedConnection
  • 如果在多线程时,若强制设定参数为Qt::DirectConnection,那么多线程将失效,子线程的处理函数仍在主线程中
  • 所以才需要通过connect来实现多线程,因为其内部已经有这样的一个实现多线程的机制
  • 队列:槽函数所在线程和接收者一样
  • 直接:槽函数所在线程和发送者一样

你可能感兴趣的:(Qt)