QT多线程的实现方式:QThread run优雅的创建与退出【QT多线程】

qt通过继承实现线程的方法有两种

  1. 继承QThread,然后重写run函数实现多线程
  2. 继承QObject,使用moveToThread函数实现多线程

本文介绍第一种的创建、使用与退出。

一、QThread类的run介绍

1、QThread::run函数的使用

QThread 是用来管理线程的,它所依附的线程和它管理的新线程并不是同一个东西QThread 所依附的线程,就是执行创建QThread的线程。也就是咱们这儿的主线程,QThread 管理的新线程,就是 run 启动的线程。

所以总结一句话:QThread只有run函数是在新线程里的,其他所有函数都在QThread生成的线程里

那么就抛出两个问题

1.QThread的对象依附在主线程中,次线程的slot函数会在主线程中执行,而不是次线程。除非:(不建议这样做)

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

三、优雅的停止创建的线程

quitexit函数都不会中途终端线程,要马上终止一个线程可以使用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);
   }
 }

 

 

 

 

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Qt对线程提供了支持,基本形式有独立于平台的线程类、线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法。 这个文档是提供给那些对多线程编程有丰富的知识和经验的听众的。推荐阅读: Threads Primer: A Guide to Multithreaded Programming Thread Time: The Multithreaded Programming Guide Pthreads Programming: A POSIX Standard for Better Multiprocessing (O'Reilly Nutshell) Win32 Multithreaded Programming 警告:所有的GUI类(比如,QWidget和它的子类),操作系统核心类(比如,QProcess)和网络类都不是线程安全的。 QRegExp使用一个静态缓存并且也不是线程安全的,即使通过使用QMutex来保护的QRegExp对象。 启用线程支持 在Windows上安装Qt时,在一些编译器上线程支持是一个选项。 在Mac OS X和Unix上,线程支持可以当你在运行configure脚本时添加-thread选项就可以生效了。在Unix平台上,多线程程序必须用特殊的方式连接,比如使用特殊的libc,安装程序将会创建另外一个库libqt-mt并且因此线程程序必须和这个库进行连接(使用-lqt-mt)而不是标准的Qt库。 在两个平台上,你都应该定义宏QT_THREAD_SUPPORT来编译(比如,编译时使用-DQT_THREAD_SUPPORT)。在Windows上,这个通常可以在qconfig.h写一个条目来解决。 线程类 最重要的类是QThread,也就是说要开始一个新的线程,就是开始执行你重新实现QThread::run()。这和Java的线程类很相似。 为了写线程程序,在两个线程同时希望访问同一个数据时,对数据进行保护是很必要的。因此这里也有一个QMutex类,一

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吻等离子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值