百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

Qt推荐的多线程的理解 qt开多线程

liebian365 2024-11-12 13:10 7 浏览 0 评论

目的

在Qt4.8之后,Qt多线程的写法最好还是通过QObject来实现,和线程的交互通过信号和槽(实际上其实是通过事件)联系。

用QObject来实现多线程有个非常好的优点,就是默认就支持事件循环(Qt的许多非GUI类也需要事件循环支持,如QTimer、QTcpSocket),QThread要支持事件循环需要在QThread::run()中调用QThread::exec()来提供对消息循环的支持,否则那些需要事件循环支持的类都不能正常发送信号,因此如果要使用信号和槽,那就直接使用QObject来实现多线程。

使用QObject创建多线程的方法如下:

写一个继承QObject的类,对需要进行复杂耗时逻辑的入口函数声明为槽函数

此类在旧线程new出来,不能给它设置任何父对象

同时声明一个QThread对象,在官方例子里,QThread并没有new出来,这样在析构时就需要调用QThread::wait(),如果是堆分配的话, 可以通过deleteLater来让线程自杀

把obj通过moveToThread方法转移到新线程中,此时object已经是在线程中了

把线程的finished信号和object的deleteLater槽连接,这个信号槽必须连接,否则会内存泄漏

正常连接其他信号和槽(在连接信号槽之前调用moveToThread,不需要处理connect的第五个参数,否则就显示声明用Qt::QueuedConnection来连接)

初始化完后调用'QThread::start()'来启动线程

在逻辑结束后,调用QThread::quit退出线程的事件循环

使用QObject来实现多线程比用继承QThread的方法更加灵活,整个类都是在新的线程中,通过信号槽和主线程传递数据。

情况

Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。两种方法区别不大,用起来都比较方便,但继承QObject的方法更加灵活。这里要记录的是如何正确的创建一个线程,特别是如何正确的退出一个线程。

一开始不理解其是怎么实现的,所以不太愿意用,理解其如何实现的,会发现这种用法,的确非常的好。

官网这样描述的:

QThread类提供了一种独立于平台的方式来管理线程。

QThread对象管理程序中的一个控制线程。QThreads在run()中开始执行。默认情况下,run()通过调用exec()启动事件循环,

并在线程内运行Qt事件循环。

您可以通过使用QObject::moveToThread()将工作对象移动到线程中来使用它们。

然后,Worker槽内的代码将在单独的线程中执行。然而,你可以自由地将Worker的插槽连接到任何信号,

来自任何对象,任何线程。由于一种称为排队连接的机制,跨不同线程连接信号和插槽是安全的。

例子如下:

cotroller的源码:

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <QObject>
#include <QThread>
#include "worker.h"

class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;
public:
    explicit Controller(QObject *parent = nullptr);
    ~Controller();
    void beginOperate();
public slots:
     void handleResults(const QString &str);
signals:
     void operate(const QString &);
};

#endif // CONTROLLER_H
#include "controller.h"

Controller::Controller(QObject *parent) : QObject(parent)
{
  Worker *worker = new Worker;
  worker->moveToThread(&workerThread);
  connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
  connect(this, &Controller::operate, worker, &Worker::doWork);
  connect(worker, &Worker::resultReady, this, &Controller::handleResults);
  workerThread.start();
}

Controller::~Controller()
{
  workerThread.quit();
  workerThread.wait();
}

void Controller::beginOperate()
{
    QString str = "begin";
    emit operate(str);
}

void Controller::handleResults(const QString &str)
{
   qDebug("enter function Controller::handleResults str=%s", str.toStdString().c_str());
   QThread *currentThread = QThread::currentThread();
   qDebug("exit function Controller::handleResults currentThread=%p", currentThread);
}

worker的源码:

#ifndef WORKER_H
#define WORKER_H

#include <QObject>

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);

signals:
    void resultReady(const QString &result);

public slots:
    void doWork(const QString ?meter);
};

#endif // WORKER_H
#include "worker.h"
#include <QThread>

Worker::Worker(QObject *parent) : QObject(parent)
{

}

void Worker::doWork(const QString ?meter)
{
 qDebug("enter function Worker::doWork parameter=%s", parameter.toStdString().c_str());
 QString result;
 /* ... here is the expensive or blocking operation ... */
 result = "executing";
 emit resultReady(result);
 QThread *currentThread = QThread::currentThread();
 qDebug("exit function Worker::doWork currentThread=%p", currentThread);
}

main函数:

#include <QCoreApplication>
#include "controller.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Controller *controller = new Controller();
    controller->beginOperate();
    return a.exec();
}

执行情况:


可以见得,是运行在不同的线程内,


总结

其理解的关键就是在于thread默认运行着exec(),时刻监听着事件队列的情况,如果队列里有事件,就取出来执行;

有了这一个事件队列,可比原来直接在run()当中执行方便多了,这样也理解了moveToThread方法的含义,其含义就是把整个对象放到这一个线程里,这个线程通过exec()监听着事件队列,如果事件队列有事件,就取出来执行,非常的方便,当然也可以放一个QTimer控件在线程里,进行定时执行,也是可以的。

最后用一图进行总结:


相关推荐

快递查询教程,批量查询物流,一键管理快递

作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...

一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递

对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...

快递查询单号查询,怎么查物流到哪了

输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...

3分钟查询物流,教你一键批量查询全部物流信息

很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...

快递单号查询,一次性查询全部物流信息

现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...

快递查询工具,批量查询多个快递快递单号的物流状态、签收时间

最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...

快递查询软件,自动识别查询快递单号查询方法

当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...

教你怎样查询快递查询单号并保存物流信息

商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...

简单几步骤查询所有快递物流信息

在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...

物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号

最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...

连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息

快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...

快递查询教程,快递单号查询,筛选更新量为1的单号

最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...

掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析

在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...

从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息

在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...

物流单号查询,在哪里查询快递

如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...

取消回复欢迎 发表评论: