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

QT(11)- QThread qt 使用c++ thread

liebian365 2024-10-17 14:00 28 浏览 0 评论

1 简介

QThread:具有可选事件循环的低级 API
QThread是 Qt 中所有线程控制的基础。每个QThread实例表示并控制一个线程。

QThread可以直接实例化,也可以子类化。实例化QThread提供了一个并行事件循环,允许在辅助线程中调用QObject插槽。对 QThread进行子类化允许应用程序在启动其事件循环之前初始化新线程,或者在没有事件循环的情况下运行并行代码。

QThread 会在线程运行时通过信号通知你started() 和finished(), 或者你可以使用isFinished() 和isRunning() 来查询线程的状态。

您可以通过调用停止线程exit() 或者quit(). 在极端情况下,您可能想要强行terminate() 一个正在执行的线程。然而,这样做是危险的。

使用wait() 阻塞调用线程,直到另一个线程完成执行(或直到指定的时间过去)。

QThread 还提供静态的、平台独立的休眠函数:sleep(),msleep(), 和usleep() 分别允许完整的秒、毫秒和微秒分辨率。

2 枚举

3 函数

3.1 eventDispatch

QAbstractEventDispatcher *QThread::eventDispatcher() const
它返回线程内部的事件分发器。
事件分发器是Qt内部使用的对象,用于分发事件到与线程关联的对象。它是Qt事件系统的一部分,在应用程序的主线程中,事件分发器会在事件循环中不断地分发事件。在其他线程中,事件分发器用于处理线程相关的事件,例如,线程完成信号或其他自定义事件。

通过使用这个函数,可以访问该线程内部的事件分发器,并对其进行配置或访问。但是,一般情况下,不需要直接访问事件分发器。

void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
setEventDispatcher 是QThread类中的一个成员函数,用于在线程中设置一个事件分发器。

这个函数接受一个QAbstractEventDispatcher指针作为参数,并将其设置为线程的事件分发器。事件分发器是Qt内部使用的对象,用于处理线程内部的事件。通过使用这个函数,可以为线程定制事件分发器,以满足特定需求。

一般情况下,不需要使用这个函数,因为Qt会自动为每个线程分配一个适当的事件分发器。但是,如果需要定制线程内部的事件处理,则可以使用这个函数。

3.2 exit

void QThread::exit(int returnCode = 0)
exit 函数告诉线程的事件循环(不是线程)退出,并以一个返回码作为结果。

调用此函数后,该线程离开事件循环并从调用 QEventLoop::exec() 的地方返回。 QEventLoop::exec() 函数的返回值为 returnCode。

按照惯例,returnCode 为0表示成功,任何非零值表示错误。

请注意,与同名的C库函数不同,该函数确实返回给调用者,因为是事件处理停止了。

在此线程中,不会再启动任何QEventLoop,直到再次调用 QThread::exec()。如果 QThread::exec() 中的事件循环没有运行,则下一次调用 QThread::exec() 也将立即返回。

使用该函数的常见场景是在线程中执行任务完成后终止线程的执行,以避免在没有任务的情况下继续执行无用代码。

3.3 isfinished

bool QThread::isFinished() const
该函数用于检查线程是否已经结束。如果线程已结束,则返回 true,否则返回 false。

线程的结束是指该线程的 run() 函数已经返回。因此,在线程结束后,如果再次调用该函数,它将返回 true。

3.4 requestInterruption

bool isInterruptionRequested() const
如果应该停止在此线程上运行的任务,则返回 true。可以通过以下方式请求中断requestInterruption().

此功能可用于使长时间运行的任务完全可中断。永远不要检查或操作此函数返回的值是安全的,但建议在长时间运行的函数中定期这样做。注意不要过于频繁地调用它,以保持较低的开销。

该函数返回一个布尔值,表示线程是否被请求中断。

应用场景:当我们需要在线程运行时随时取消它,可以使用该函数来实现。

方法:

首先需要在线程的实现中,定期调用该函数,如果函数返回 true,表示线程被请求中断。
然后退出线程的循环,让线程终止。

void MyThread::run()
{
while (!isInterruptionRequested())
{
//do some work
//check periodically if the thread needs to be stopped
}
}
QThread *thread = new QThread;
thread->start();
//Later, in another thread
thread->requestInterruption();

void requestInterruption()
请求中断线程。该请求是建议性的,由线程上运行的代码决定是否以及如何响应此类请求。此函数不会停止线程上运行的任何事件循环,也不会以任何方式终止它。

3.5 isRunning

bool QThread::isRunning() const
true如果线程正在运行则返回;否则返回false。

3.4 loopLevel

int QThread::loopLevel() const
QThread::loopLevel() 函数是 Qt 库中的成员函数,用于返回当前线程的事件循环深度。事件循环深度指的是在当前线程中有多少个事件循环正在执行。

例如,如果当前线程中有一个事件循环正在执行,那么 QThread::loopLevel() 函数将返回 1;如果当前线程中有两个事件循环正在执行,那么函数将返回 2,以此类推。

可以通过这个函数来判断线程中是否存在事件循环,从而决定是否执行一些特定的操作。

3.5 priority

QThread::Priority QThread::priority() const
返回正在运行的线程的优先级。如果线程未运行,则此函数返回InheritPriority

void setPriority(QThread::Priority priority)
这个函数用于设置正在运行的线程的优先级。如果线程没有运行,则此函数什么也不做,并立即返回。要以特定优先级启动线程,请使用start()。

priority参数可以是QThread :: Priority枚举中的任何值,除了InheritPriority。

优先级参数的效果取决于操作系统的调度策略。特别是,在不支持线程优先级的系统上(例如Linux)

3.6 StackSize 堆栈大小

void QThread::setStackSize(uint stackSize)
这个函数用于设置线程的堆栈大小。如果线程正在运行,则此函数不会有任何效果,并立即返回。如果要以特定的堆栈大小启动线程,请使用start()。

stackSize参数是堆栈大小,以字节为单位。默认堆栈大小取决于操作系统,通常为2 MB。

注意:在某些操作系统上,设置堆栈大小不受支持,在这些系统上,该函数可能不起作用,因此需要检查该函数的返回值。

uint QThread::stackSize() const
返回线程的最大堆栈大小(如果设置为setStackSize()); 否则返回零。

3.7 wait

bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever))
这个函数会等待线程结束,直到 deadline 到期。
bool wait(unsigned long time)
这个函数会等待线程结束,最多等待 time 毫秒。

如果在等待期间线程已经结束,那么两个函数都会立即返回 true。否则,如果等待超时或者等待被其他线程中断,那么它们将返回 false。

如果等待的时间到了,但是线程还没有结束,那么 wait() 函数将返回 false。这表示在等待的过程中,线程没有终止,因此不需要等待

4 虚函数

virtual bool event(QEvent *event) override

event() 是 QObject 类中的虚拟函数,在继承类中被重写可以自定义处理事件。QThread 继承自 QObject,所以也可以重写 event() 函数。

event() 函数通过接收到的 QEvent 对象参数来处理不同类型的事件。这样,你可以定制线程的行为,比如,当线程接收到一个特定的事件时,它可以做出特定的反应。

在 event() 函数中,你可以对事件进行判断,根据事件类型执行不同的操作。如果 event() 函数返回 true,那么这个事件就被认为已经处理过;否则,事件会继续传递到父对象。

注意:QThread 不是一个 GUI 线程,所以不能在它的 event() 函数中调用 GUI 函数(例如:QMessageBox)。如果需要在线程中调用 GUI 函数,请使用 signals 和 slots。

5 Public Slots

5.1 quit

void quit()
告诉线程的事件循环以返回码 0(成功)退出。相当于调用QThread::exit(0).
如果线程没有事件循环,则此函数不执行任何操作。

5.2 start

void start(QThread::Priority priority = InheritPriority)
通过调用开始执行线程run(). 操作系统会根据priority范围。如果线程已经在运行,则此函数不执行任何操作。
的影响priority参数取决于操作系统的调度策略。特别是,priority在不支持线程优先级的系统上将被忽略(例如在 Linux 上)

因为优先级需要在线程运行的时候设置,所以如果需要设置优先级,可以在使用start时就直接设置。

5.3 terminate

void terminate()
这个函数是用来终止线程的执行的。根据操作系统的调度策略,线程可能立刻终止,也可能不会。在使用terminate()函数后,使用QThread::wait()来确保线程已经终止。

当线程终止时,所有等待该线程结束的线程将被唤醒。

注意,使用 "terminate()" 终止线程是不推荐的,因为它可能导致线程执行未完成的任务,导致程序状态不一致。正确的做法是在线程执行代码中设置标志,让线程自行退出

6 信号

void finished()
finished() 是 QThread 类的信号,在线程结束后发出。这个信号通常用来在线程结束后释放相关资源,或执行清理操作。

换句话说,它是一个通知,告诉线程的使用者,线程已经结束了。

这个信号可以连接到QObject::deleteLater(), 以释放该线程中的对象。

注意:如果关联的线程被终止使用terminate(), 未定义从哪个线程发出该信号。

注意:这是一个私人信号。它可用于信号连接,但不能由用户发射。

void started()
当相关线程开始执行时,在调用run()函数之前,该信号从线程发出。

注意:这是一个私有信号。它可用于信号连接,但不能由用户发出。

7 静态公有函数

7.1 create

QThread * create(Function &&f, Args &&... args)
c++17标准适用

template <typename Function> QThread *QThread::create(Function &&f)
创建一个新的QThread对象,它将执行函数f。

新线程没有启动——它必须通过显式调用start()来启动。这允许您连接到它的信号,将QObjects移动到线程,选择新线程的优先级等等。函数f将在新线程中被调用。

返回新创建的QThread实例。

注意:调用者获得返回的QThread实例的所有权。

警告:不要在返回的QThread实例上调用start()超过一次;这样做将导致未定义的行为。

7.2 currentThread

QThread * currentThread()
返回一个指向QThread的指针,该QThread管理当前执行的线程

7.3 currentThreadId

Qt::HANDLE currentThreadId()
返回当前执行线程的线程句柄。

警告:此函数返回的句柄用于内部目的,不应在任何应用程序代码中使用。

注意:在Windows上,这个函数返回由Win32函数GetCurrentThreadId()返回的DWORD (Windows- thread ID),而不是由Win32函数GetCurrentThread()返回的伪句柄(Windows- thread句柄)。

7.4 idealThreadCount

int idealThreadCount()
返回系统上可以运行的理想线程数。这是通过查询系统中实际的和逻辑的处理器内核数量来完成的。如果无法检测到处理器核数,则此函数返回1。

7.5 sleep

void msleep(unsigned long msecs)
强制当前线程休眠msecs毫秒。

如果需要等待给定条件的改变,请避免使用此函数。相反,将插槽连接到指示更改的信号或使用事件处理程序(参见QObject::event())。

注意:此函数不保证准确性。在重载条件下,应用程序的睡眠时间可能超过msec。一些操作系统可能把毫秒四舍五入到10毫秒或15毫秒。

void sleep(unsigned long secs)

void usleep(unsigned long usecs)
微秒

7.6 yieldCurrentThread

void yieldCurrentThread()
将当前线程的执行传递给另一个可运行的线程(如果有的话)。注意,由操作系统决定切换到哪个线程。

8 Protected Functions

8.1 exec

int exec()
进入事件循环并等待,直到调用exit(),返回传递给exit()的值。如果通过quit()调用exit(),则返回值为0。

该函数将在run()中调用。必须调用此函数来启动事件处理。

注意:这只能在线程本身中调用,即当它是当前线程时。

8.2 run

virtual void run()
线程的起始点。在调用start()之后,新创建的线程调用这个函数。默认实现只调用exec()。

您可以重新实现此函数以方便高级线程管理。从这个方法返回将结束线程的执行。

9 Static Protected Members

void setTerminationEnabled(bool enabled = true)
基于enabled参数启用或禁用当前线程的终止。线程必须是由QThread启动的。

当enabled为false时,终止被禁用。以后对QThread::terminate()的调用将立即返回而不生效。相反,终止将被推迟,直到启用终止。

当enabled为true时,终止被启用。以后对QThread::terminate()的调用将正常终止线程。如果终止被延迟(即QThread::terminate()在终止被禁用的情况下被调用),该函数将立即终止调用线程。注意,这个函数在这种情况下不会返回。

相关推荐

go语言也可以做gui,go-fltk让你做出c++级别的桌面应用

大家都知道go语言生态并没有什么好的gui开发框架,“能用”的一个手就能数的清,好用的就更是少之又少。今天为大家推荐一个go的gui库go-fltk。它是通过cgo调用了c++的fltk库,性能非常高...

旧电脑的首选系统:TinyCore!体积小+精简+速度极快,你敢安装吗

这几天老毛桃整理了几个微型Linux发行版,准备分享给大家。要知道可供我们日常使用的Linux发行版有很多,但其中的一些发行版经常会被大家忽视。其实这些微型Linux发行版是一种非常强大的创新:在一台...

codeblocks和VS2019下的fltk使用中文

在fltk中用中文有点问题。英文是这样。中文就成这个样子了。我查了查资料,说用UTF-8编码就行了。edit->Fileencoding->UTF-8然后保存文件。看下下边的编码指示确...

FLTK(Fast Light Toolkit)一个轻量级的跨平台Python GUI库

FLTK(FastLightToolkit)是一个轻量级的跨平台GUI库,特别适用于开发需要快速、高效且简单界面的应用程序。本文将介绍Python中的FLTK库,包括其特性、应用场景以及如何通过代...

中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux

IT之家1月29日消息,去年6月份,中科院大学教授、中科院计算所研究员包云岗,发布了开源高性能RISC-V处理器核心——香山。近日,包云岗在社交平台晒出图片,香山芯片已流片,回片后...

Linux 5.13内核有望合并对苹果M1处理器支持的初步代码

预计Linux5.13将初步支持苹果SiliconM1处理器,不过完整的支持工作可能还需要几年时间才能完全完成。虽然Linux已经可以在苹果SiliconM1上运行,但这需要通过一系列的补丁才能...

Ubuntu系统下COM口测试教程(ubuntu port)

1、在待测试的板上下载minicom,下载minicom有两种方法:方法一:在Ubuntu软件中心里面搜索下载方法二:按“Ctrl+Alt+T”打开终端,打开终端后输入“sudosu”回车;在下...

湖北嵌入式软件工程师培训怎么选,让自己脱颖而出

很多年轻人毕业即失业、面试总是不如意、薪酬不满意、在家躺平。“就业难”该如何应对,参加培训是否能改变自己的职业走向,在湖北,有哪些嵌入式软件工程师培训怎么选值得推荐?粤嵌科技在嵌入式培训领域有十几年经...

新阁上位机开发---10年工程师的Modbus总结

前言我算了一下,今年是我跟Modbus相识的第10年,从最开始的简单应用到协议了解,从协议开发到协议讲解,这个陪伴了10年的协议,它一直没变,变的只是我对它的理解和认识。我一直认为Modbus协议的存...

创建你的第一个可运行的嵌入式Linux系统-5

@ZHangZMo在MicrochipBuildroot中配置QT5选择Graphic配置文件增加QT5的配置修改根文件系统支持QT5修改output/target/etc/profile配置文件...

如何在Linux下给zigbee CC2530实现上位机

0、前言网友提问如下:粉丝提问项目框架汇总下这个网友的问题,其实就是实现一个网关程序,内容分为几块:下位机,通过串口与上位机相连;下位机要能够接收上位机下发的命令,并解析这些命令;下位机能够根据这些命...

Python实现串口助手 - 03串口功能实现

 串口调试助手是最核心的当然是串口数据收发与显示的功能,pzh-py-com借助的是pySerial库实现串口收发功能,今天痞子衡为大家介绍pySerial是如何在pzh-py-com发挥功能的。一、...

为什么选择UART(串口)作为调试接口,而不是I2C、SPI等其他接口

UART(通用异步收发传输器)通常被选作调试接口有以下几个原因:简单性:协议简单:UART的协议非常简单,只需设置波特率、数据位、停止位和校验位就可以进行通信。相比之下,I2C和SPI需要处理更多的通...

同一个类,不同代码,Qt 串口类QSerialPort 与各种外设通讯处理

串口通讯在各种外设通讯中是常见接口,因为各种嵌入式CPU中串口标配,工业控制中如果不够还通过各种串口芯片进行扩展。比如spi接口的W25Q128FV.对于软件而言,因为驱动接口固定,软件也相对好写,因...

嵌入式linux为什么可以通过PC上的串口去执行命令?

1、uboot(负责初始化基本硬bai件,如串口,网卡,usb口等,然du后引导系统zhi运行)2、linux系统(真正的操作系统)3、你的应用程序(基于操作系统的软件应用)当你开发板上电时,u...

取消回复欢迎 发表评论: