【Qt】Qt多线程开发—实现多线程设计的四种方法

Qt—使用Qt实现多线程设计的四种方法

一、写在前面

​ 这篇文章内容是:关于Qt多线程应用设计的。
在Qt中提供了四种方法来进行多线程编程和设计。合理的选择对应的方法来满足实际开发中的应用场景。

二、【方法一】 QThread:带有可选事件循环的底层API

QThread是Qt中所有线程控件的基础,每个QThread实例代表和控制着一个线程。使用QThread创建线程有两种方法:1)、可以直接实例化创建,2)也可以子类化它进行线程创建。

1、实例化QThread:提供了一个并行事件循环,允许在辅助线程中调用QObject槽函数。

2、继承QThread:允许应用程序在启动事件循环之前初始化新线程,或者在没有事件循环的情况下运行并行代码。

三、【方法二】 QThreadPool和QRunnable:重用线程

​ 频繁的创建和销毁线程的代价可能会很高。为了减少这种开销,可以对新任务重用现有的线程。QThreadPool是可重用QThreads的集合。

要在QThreadPool的一个线程中运行代码,需要重新实现QRunnable::run()并实例化子类化的QRunnable

使用````QThreadPool::start()```将QRunnable放到QThreadPool的运行队列中。当线程可用时,QRunnable::run()中的代码将在该线程中执行。

【备注】:每个Qt应用程序都有一个全局线程池,可以通过QThreadPool::globalInstance()访问它。这个全局线程池根据CPU中的核心数量将自动维护最佳的线程数量。但是,在实际开发中,也可以显式地创建和管理一个单独的QThreadPool

四、【方法三 】Qt并发:使用高级API

​ Qt并发模块提供了许多高级功能,用来处理一些常见的并行计算模式。例如:mapfilterreduce。Qt并发与使用QThreadQRunnable不同,这些函数不需要使用底层的线程原语,如互斥或信号量等。相反,它们返回的是一个QFuture对象,该对象可用于在线程准备或者完成时自动检索函数的结果;QFuture还可以用来查询、计算进度和暂停/恢复/取消计算。为了方便起见,QFutureWatcher允许通过信号和槽与QFutures进行交互。

​ Qt Concurrent的并行计算模型:mapfilterreduce等算法自动将计算分配到所有可用的处理器核心上,因此,我们今天编写的应用程序在以后部署到拥有更多内核的系统时将继续得以扩展和使用,这非常方便。

​ 这个模块还提供了QtConcurrent::run()函数,它可以在另一个线程中运行任何的函数。但是,QtConcurrent::run()只支持mapfilterreduce函数可用的特性子集,QFuture可用于检索函数的返回值并检查线程是否正在运行。

​ 但是,对QtConcurrent::run()的调用只使用一个线程,不能暂停/恢复/取消,也不能查询进程。

五、【方法四】 WorkerScript:QML中的线程化

WorkerScriptQML类型允许JavaScript代码与GUI线程并行运行。每个WorkerScript实例可以附加一个.js脚本。调用WorkerScript.sendMessage()时,脚本将在单独的线程(和单独的QML上下文)中运行。当脚本运行完成时,它可以将一个回复发送回GUI线程,该线程将调用WorkerScript.onMessage()信号处理程序。

使用WorkerScript类似于使用已移动到另一个线程的worker QObject,数据通过信号在线程之间进行传输。

【注】这种方法在QML中使用

六、如何选择上述四种不同的多线程设计的解决方案

​ 如上所示,Qt为开发多线程应用程序提供了不同的解决方案。对于多线程应用程序的正确解决方案取决于:新线程的用途和线程的生命周期。下面是Qt几种多线程技术机制的比较:

序号特点QThreadQRunnable 和QThreadPoolQtConcurrent::run()Qt Concurrent(Map/Filter/Reduce)WorkerScript
1开发语言C++C++C++C++QML
2是否可以指定线程优先级YesYes
3线程是否可以运行一个事件循环Yes
4线程通过信号接收数据更新Yes (received by a worker QObject)Yes (received by WorkerScript)
5线程是否可以使用信号来控制Yes (received by QThread)Yes (received by QFutureWatcher)
6线程是否可以通过QFuture来监控部分地Yes
7是否拥有内置能力:取消/暂停/恢复Yes
七、Qt多线程应用设计示例
线程生命周期操作解决方法
一次调用在另一个线程中运行一个新的线性函数,可以选择在运行期间进行进度更新。Qt提供了不同的解决方案: 将该函数放在QThread::run()的重新实现中,并启动QThread。发出信号更新进度。将该函数放在QRunnable::run()的重新实现中,并将QRunnable添加到QThreadPool中。写入线程安全的变量以更新进度。使用QtConcurrent:: Run()运行函数。写入线程安全的变量以更新进度。
一次调用在另一个线程中运行一个现有函数并获取它的返回值。使用QtConcurrent:: Run()运行函数。 让QFutureWatcher在函数返回时发出finished()信号,并调用QFutureWatcher::result()来获取函数的返回值。
一次调用在另一个线程中运行一个现有函数并获取它的返回值。使用QtConcurrent:: Run()运行函数。让QFutureWatcher在函数返回时发出finished()信号,并调用QFutureWatcher::result()来获取函数的返回值。
一次调用使用所有可用的内核对容器(Container)的所有项执行操作。例如,从图像列表生成缩略图。使用QtConcurrent的QtConcurrent::filter()函数来选择容器元素,使用QtConcurrent::map()函数来对每个元素应用一个操作。要将输出换算成单个结果,可以使用QtConcurrent:: filteredreduce()和QtConcurrent::mappedReduced()。
一次调用/永久存在在纯QML应用程序中完成长时间的计算,并在结果准备好时更新GUI。将计算代码放在.js脚本中,并将其附加到WorkerScript实例。调用WorkerScript.sendMessage()在新线程中启动计算。让脚本也调用sendMessage(),将结果传递回GUI线程。在onMessage中处理结果并在那里更新GUI。
永久存在在另一个线程中有一个对象,它可以根据请求执行不同的任务,并且/或者可以接收新的数据来处理。子类化一个QObject来创建一个worker。实例化这个worker对象和一个QThread。将worker移动到新线程。通过排队的信号和槽连接向worker对象发送命令或数据。
永久存在在另一个线程中重复执行开销较大的操作,其中该线程不需要接收任何信号或事件。直接在QThread::run()的重新实现中写入无限循环。在没有事件循环的情况下启动线程。让线程发出信号将数据发送回GUI线程。

搜索/关注【嵌入式小生】vx公众号,获取更多精彩内容>>>>
请添加图片描述

  • 7
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt Creator 多线程读取文件到程序显示 利用QT Creator多任务读取一个文档到程序里 为了防止直接读取文件里的内容太大而发生卡顿,于是多线程读取将更高效的解决这个问题。 效果图如下: 其中pro文件无需改动,默认就好,头文件h里面的内容为 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MyObj; class MyObj : public QObject { Q_OBJECT public: MyObj(); //新的线程 signals: void toLine(QString line); private slots: void doWork(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void appendText(QString); //定义一个槽 private: Ui::MainWindow *ui; QThread *t; MyObj *obj; }; #endif // MAINWINDOW_H 而MAIN主文件的内容为了防止中文乱码做了如下修改: #include "mainwindow.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); //设置中文字体 防止乱码 a.setFont(QFont("Microsoft Yahei", 9)); //设置中文编码 #if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) #if _MSC_VER QTextCodec *codec = QTextCodec::codecForName("GBK"); #else QTextCodec *codec = QTextCodec::codecForName("UTF-8"); #endif QTextCodec::setCodecForLocale(codec); QTextCodec::setCodecForCStrings(codec); QTextCodec::setCodecForTr(codec); #else QTextCodec *codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForLocale(codec); #endif MainWindow w; w.show(); return a.exec(); } 接下来重点来了,源文件CPP里为 #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); t = new QThread(); //QThread obj = new MyObj(); obj->moveToThread(t); qDebug()<<"main thread:"<<QThread::currentThread(); connect(t,SIGNAL(started()), obj, SLOT(doWork())); connect(obj,SIGNAL
Qt是一种广泛使用的C++跨平台应用程序开发框架,主要用于开发GUI程序。Qt提供了串口通信的相关类和函数,同时也支持多线程开发Qt的串口通信类中,最重要的类是QSerialPort,它提供了一系列与串口通信相关的函数,包括打开串口、设置串口参数、读取数据、写入数据等。而对于多线程开发,在Qt中通常使用QThread类来创建线程。在串口通信多线程开发中,可以使用QThread类创建一个新的线程来处理串口通信,从而提高程序的并发性和稳定性。可以使用Qt的信号和槽机制来实现不同线程之间的通讯和数据传递。同时,在多线程开发中需要注意线程的同步和互斥,以避免多线程访问同一资源造成的冲突和数据损坏。 Qt串口多线程开发的源码实现需要先创建一个串口通信类,然后继承QThread类创建一个新的线程,在该线程中调用串口通信类的函数进行通讯。在实现过程中需要使用信号和槽机制来实现不同线程之间的通讯和数据传递,同时也需要考虑线程的同步和互斥问题,以避免多线程访问同一资源造成的冲突和数据损坏。 总之,Qt提供了非常完善的串口通信和多线程开发的支持,并且在实现过程中也比较简单,只需要熟悉Qt的相关类和函数即可。同时,在开发过程中也需要遵循一些基本的原则,如线程安全、代码可读性等,以确保程序的质量和可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值