QT 关于使用QThread实现多线程(重写run函数)
在QT中,有两种多线程的方法,一种是继承QThread的run函数,另一种是把一个继承于QObject的类转移到一个Thread里。
Qt4.8之前都是使用继承QThread的run这种方法(本次主要介绍的就是这种),其主要步骤如下:
0x01、新建一个类(WorkThread),把该类的父类改为QThread
0x02、重写QThread的run函数,在run函数中搞事情(耗时操作)
0x03、在需要使用的地方,new一个子线程,然后调用QThread的 start 方法启动线程。
0x04、如果需要结束线程,则使用QThread的 wait 方法。
示例代码如下(workthread为子线程,maindialog为调用者):
workthread.h
#ifndef WORKTHREAD_H
#define WORKTHREAD_H
#include <QObject>
#include <QThread>
class WorkThread : public QThread/*QObject*/
{
Q_OBJECT
public:
explicit WorkThread(QObject *parent = 0);
signals:
void currentNum(int);
void workDone();
public slots:
void stopThread();
protected:
virtual void run();
private:
volatile bool bStop = false;//易失性变量,用volatile进行申明
};
#endif // WORKTHREAD_H
workthread.cpp
#include "workthread.h"
#include <QDebug>
#include <QMessageBox>
WorkThread::WorkThread(QObject *parent) : QThread(parent)
{
}
void WorkThread::run()
{
//注意:在子线程中不能出现跟UI相关的代码(QMessageBox这些都不行)
//ASSERT failure in QWidget: "Widgets must be created in the GUI thread.",
//QMessageBox::information(NULL, "info", "I'm sub thread");
//do something...
for(int i=0; i<10; i++)
{
if(bStop == false)
{
QThread::msleep(500);
qDebug() << "SubThreadId:" << QThread::currentThreadId() << "i:" << i;
emit currentNum(i);
}
}
emit workDone();
}
void WorkThread::stopThread()
{
bStop = true;
}
maindialog.h
#ifndef MAINDIALOG_H
#define MAINDIALOG_H
#include <QDialog>
class MainDialog : public QDialog
{
Q_OBJECT
public:
MainDialog(QWidget *parent = 0);
~MainDialog();
public slots:
void onCurrentNum(int);
void onWorkDone();
};
#endif // MAINDIALOG_H
maindialog.cpp
#include "maindialog.h"
#include "workthread.h"
#include <QPushButton>
#include <QDebug>
MainDialog::MainDialog(QWidget *parent)
: QDialog(parent)
{
//创建"开始"按钮 按照控件的大小创建窗口
QPushButton * btnStart = new QPushButton("Start", this);
//移动btnStart按钮
btnStart->move(100,100);
//调整按钮大小
btnStart->resize(100,50);
//创建"停止"按钮 按照控件的大小创建窗口
QPushButton * btnStop = new QPushButton("Stop", this);
//移动btnStop按钮
btnStop->move(300,100);
//调整按钮大小
btnStop->resize(100,50);
//重置窗口大小
resize(600,400);
//设置固定窗口大小
setFixedSize(600,400);
//设置窗口标题
setWindowTitle("QThread Test");
WorkThread *pWork = new WorkThread(this);
//Qt4版本的写法
// connect(pWork,SIGNAL(currentNum(int)),this, SLOT(onCurrentNum(int)));
// connect(pWork,SIGNAL(workDone()),this, SLOT(onWorkDone()));
//连接带参数的信号和槽(函数指针的写法)
// void(WorkThread:: *currentNumSigal)(int) = &WorkThread::currentNum;
// void(MainDialog:: *currentNumSlot)(int) = &MainDialog::onCurrentNum;
// connect(pWork, currentNumSigal, this, currentNumSlot);
// void(WorkThread:: *workDoneSigal)(void) = &WorkThread::workDone;
// void(MainDialog:: *workDoneSlot)(void) = &MainDialog::onWorkDone;
// connect(pWork, workDoneSigal, this, workDoneSlot);
//Qt5版本写法(Lambda表达式)
connect(pWork, &WorkThread::currentNum, [=](int val){
this->onCurrentNum(val);
});
connect(pWork, &WorkThread::workDone, [=](){
this->onWorkDone();
});
//关联Start和Stop按钮的信号和槽
connect(btnStart, &QPushButton::clicked, [=](){
qDebug() << "MainThreadId:" << QThread::currentThreadId();
pWork->start();//开启线程
});
connect(btnStop, &QPushButton::clicked, [=](){
pWork->stopThread();
pWork->wait();//结束线程
});
}
MainDialog::~MainDialog()
{
}
void MainDialog::onCurrentNum(int num)
{
qDebug() << "MainDialog::onCurrentNum:" << num;
}
void MainDialog::onWorkDone()
{
qDebug() << "MainDialog::onWorkDone()";
}
点击Start按钮启动线程后,然后通过stop按钮停止线程,在Qt Creator中应用程序输出:
MainThreadId: 0x2638
SubThreadId: 0x3480 i: 0
MainDialog::onCurrentNum: 0
SubThreadId: 0x3480 i: 1
MainDialog::onCurrentNum: 1
SubThreadId: 0x3480 i: 2
MainDialog::onCurrentNum: 2
SubThreadId: 0x3480 i: 3
MainDialog::onCurrentNum: 3
MainDialog::onWorkDone()
可以看到:
0x01、主线程的ThreadId跟子线程的ThreadId不是同一个,证明子线程确实是开了另外一个线程。
0x02、在子线程未执行完毕前,点击关闭程序,会提示:QThread: Destroyed while thread is still running
0x03、但是在子线程未执行完毕之前,点击了stop按钮后,程序停止了计数输出,这时关闭程序,程序不会有上述提示。
需注意的地方:
QThread实例(WorkThread)是属于创建该实例的线程的。比如在主线程中创建一个QThread,那么这个QThread实例本身属于主线程。只有子线程run函数里面定义的变量、实例等是属于新线程的。
还没有评论,来说两句吧...