QT多线程的实现方式:QThread run优雅的创建与退出【QT多线程】
qt通过继承实现线程的方法有两种
- 继承
QThread
,然后重写run
函数实现多线程- 继承
QObject
,使用moveToThread
函数实现多线程
本文介绍第一种的创建、使用与退出。
一、QThread类的run介绍
1、QThread::run函数的使用
QThread 是用来管理线程的,它所依附的线程和它管理的新线程并不是同一个东西QThread 所依附的线程,就是执行创建QThread的线程。也就是咱们这儿的主线程,QThread 管理的新线程,就是 run 启动的线程。
所以总结一句话:QThread
只有run
函数是在新线程里的,其他所有函数都在QThread
生成的线程里
那么就抛出两个问题
1.QThread的对象依附在主线程中,次线程的slot函数会在主线程中执行,而不是次线程。除非:(不建议这样做)
- QThread 对象通过movetoThread依附到次线程中(这里涉及到实现多线程的第二种方式)
- slot 和信号是直接连接,且信号在次线程中发射(这里涉及到QTconnect的第五个参数)
2.
QThread
的继承类的其他函数尽量别要有太耗时的操作,要确保所有耗时的操作都在run
函数里
2、QThread run方式特点
2.1优点:可以通过信号槽与外界进行通信。
2.2缺点:
每次新建一个线程都需要继承QThread,实现一个新类,使用不太方便。
要自己进行资源管理,线程释放和删除。并且频繁的创建和释放会带来比较大的内存开销。
2.3适用场景:QThread适用于那些常驻内存的任务。
二、QThread run实现一个简单线程
新建一个集成QThread的类,重写虚函数run,通过run启动线程
代码:https://download.csdn.net/download/qq_43445867/88332781
1、基本流程
#ifndef QTHREAD_RUN_H
#define QTHREAD_RUN_H
class QThread_Run
{
public:
QThread_Run();
};
#endif // QTHREAD_RUN_H
1.1需要创建一个线程类的子类,让其继承 QT 中的线程类 QThread,比如:
#ifndef QTHREAD_RUN_H
#define QTHREAD_RUN_H
#include <QThread>
class QThread_Run : public QThread
{
Q_OBJECT
public:
explicit QThread_Run(QObject *parent = nullptr);
QThread_Run();
};
#endif // QTHREAD_RUN_H
1.2 重写父类的 run () 方法,在该函数内部编写子线程要处理的具体的业务流程
#ifndef QTHREAD_RUN_H
#define QTHREAD_RUN_H
#include <QThread>
class QThread_Run : public QThread
{
Q_OBJECT
public:
explicit QThread_Run(QObject *parent = nullptr);
QThread_Run();
protected:
void run();
};
#endif // QTHREAD_RUN_H
1.3 在主线程中创建子线程对象,new 一个就可以了
QThread_Run* qthread_run=new QThread_Run(this);
1.4 启动子线程,调用 start () 方法
qthread_run->start();
不能在类的外部调用 run () 方法启动子线程,在外部调用 start () 相当于让 run () 开始运行
2、完整代码
qthread_run.h
#ifndef QTHREAD_RUN_H
#define QTHREAD_RUN_H
#include <QThread>
class QThread_Run : public QThread
{
Q_OBJECT
public:
explicit QThread_Run(QObject *parent = nullptr);
QThread_Run();
protected:
void run();
signals:
void result(int);
};
#endif // QTHREAD_RUN_H
qthread_run.c
#include "qthread_run.h"
#include <QEventLoop>
#include <QTimer>
QThread_Run::QThread_Run(QObject *parent): QThread(parent)
{
}
void Delay_MSec(unsigned int msec)
{
QEventLoop loop;//定义一个新的事件循环
QTimer::singleShot(msec, &loop, SLOT(quit())); //创建单次定时器,槽函数为事件循环的退出函数
loop.exec(); //事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
}
void QThread_Run::QThread_Run::run()
{
for(int i=0;i<10000;i++)
{
emit result(i);
Delay_MSec(100);
}
}
mainwindow.c
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QThread_Run* qthread_run=new QThread_Run(this);
connect(qthread_run,&QThread_Run::result,this,[=](int num)
{
ui->lcdNumber->display(num);
});
connect(ui->pushButton,&QPushButton::clicked, this, [=]()
{
qthread_run->start();
});
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "qthread_run.h"
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;
};
#endif // MAINWINDOW_H
三、优雅的停止创建的线程
quit
和exit
函数都不会中途终端线程,要马上终止一个线程可以使用terminate
函数,但这个函数存在非常不安定因素,会提示以下错误
QObject::killTimer: Timers cannot be stopped from another thread
停止创建的线程分两种情况
1、不使用事件循环
run函数内有一个 while 或 for 的死循环
最简单的方法是添加一个bool变量,设置一个标记来控制死循环的退出,通过主线程修改这个bool变量来进行终止,但这样有可能引起访问冲突,需要加锁
完整代码:https://download.csdn.net/download/qq_43445867/88332782
需要在原来的头文件加上如下语句
qthread_run.h
#ifndef QTHREAD_RUN_H
#define QTHREAD_RUN_H
#include <QThread>
class QThread_Run : public QThread
{
Q_OBJECT
public:
explicit QThread_Run(QObject *parent = nullptr);
QThread_Run();
bool m_isCanRun;//加入标志位
//加入槽函数
public slots:
void stopImmediately();
protected:
void run();
signals:
void result(int);
};
#endif // QTHREAD_RUN_H
修改源文件以及run函数
qthread_run.c
#include "qthread_run.h"
#include <QEventLoop>
#include <QTimer>
QThread_Run::QThread_Run(QObject *parent): QThread(parent)
{
}
void Delay_MSec(unsigned int msec)
{
QEventLoop loop;//定义一个新的事件循环
QTimer::singleShot(msec, &loop, SLOT(quit())); //创建单次定时器,槽函数为事件循环的退出函数
loop.exec(); //事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
}
//增加槽函数处理
void QThread_Run::stopImmediately()
{
QMutexLocker locker(&m_lock);
m_isCanRun = false;
}
void QThread_Run::QThread_Run::run()
{
for(int i=0;i<10000;i++)
{
//增加判断
QMutexLocker locker(&m_lock);
if(!m_isCanRun)//在每次循环判断是否可以运行,如果不行就退出循环
{
return;
}
emit result(i);
Delay_MSec(100);
}
}
还没有评论,来说两句吧...