Qt:QThread
0、说明
QThread提供了一种与平台无关的线程管理方法。
一个QThread对象管理一个线程。QThread通过run()方法启动线程。默认情况下,run()方法通过exec()启动一个事件循环,并且在线程中运行这个时间循环。
我们可以通过调用QObject::moveToThread()来把某项事务转移到Thread中,下面以一个Worker类为例:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(QString parameter){
QString result;
/*... 在此处填写比较重要、需要阻塞的操作 ...*/
emit resultReady(result);
} signals:
void resultReady(QString result); }; class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller(){
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(){
workerThread.quit();
workerThread.wair();
}
public slots:
void handleResults(QString);
signals:
void operate(QString);
};
在Worker类的槽函数中的代码将在另一个Thread中执行。不过,我们可以自由地在任何线程中,连接Worker的槽到任何对象的任何信号中。在不同的线程中连接信号与槽是安全的,因为才采用了队列连接的机制。
另一种使代码运行在不同的线程中的方法是,构造QThread子类,覆写run()方法,例如:
class WorkerThread : public QThread
{
Q_OBJECT
void run() override {
QString result;
/*...在这里写一些代价高昂且需要阻塞的操作...*/
emit resultReady(result);
}
signals:
void resultReady(QString);
}; void MyObject :: startWorkInAThread()
{
WorkerThread * workerThread = new WorkerThread(this);
connect(workerThread,&WorkerThread::resultReady,this,&MyObject::handleResults);
connect(workerThread,&WorkerThread::finished,workerThread,&QObject::deleteLater);
workerThread->start();
}
在本例中,线程在run()函数结束后就会退出。除非调用exec(),否则在该线程中就不会存在任何事件循环。
一个QThread对象是生存在初始化它的老线程中的,并不是存在于调用run()的新线程中,这意味着QThread的全部队列槽和调用方法都会在老线程中执行。因此,开发者如果想在新线程中调用槽函数,必须使用worker-object方法,这个槽函数不能直接在该QThread子类中实现。
不同于队列槽和调用的方法,直接在QThread中执行的方法将会在该线程中运行。当实现一个QThread子类时,在新线程中调用run()方法,但是是在老线程中构造该新线程。如果一个成员变量被多个函数调用,那么实际上该变量是被多个线程访问的,这一过程是安全的。
注意
不同线程间的Object进行交流时,要特别小心。通常情况下,函数调用应该在创建QThread的线程中进行(例如setPriority()),除非有文件说明有其他用法。
线程管理
QThread在started()和finished()时会发送一个信号,此外如果想检查的话,也可以通过isFinished()、isRunning()来检查线程的状态。
可以通过exit()、quit()来终止线程。有时,我们会想用terminate()来终止一个线程,但是这样做是危险且不推荐的。可以查看terminate()、setTerminationEnabled()来查看详细说明。
从Qt 4.8之后,可以在进程结束时,通过将finished()信号与QObject::deleteLater()连接,以释放资源。
调用wait()来阻塞一个线程,直到另一个线程finish,或者直到指定时间耗尽。
QThread也提供了一些static、平台无关的休眠函数:sleep()、msleep()、usleep(),这三个函数的功能类似,只是单位不同,分别是秒、毫秒、微秒。
注意
wait()和sleep()通常是不必要的,因为Qt是事件驱动的框架。不推荐调用wait(),可以用监听finished()信号并将它与另一个槽函数连接来代替;不推荐调用sleep(),推荐使用QTimer。
static方法currentThreadId()与currentThread()返回当前执行的线程,前一个函数返回线程ID,后一个返回线程指针。
为了选择线程名(Linux中通过ps -L命令来指定),我们可以在启动线程前调用setObjectName()。不调用该方法的话,线程名将是运行该线程的线程子类名。不过该名字在Windows系统中用release方式来编译代码时是不可用的。
1、模块和加载项
Header: | #include <QThread> |
qmake: | QT += core |
Inherits: | QObject |
2、构造与析构
QThread(QObject *parent = nullptr) |
构造一个QThread来管理一个新线程。 parent是QThread的所有者。 该线程直至调用start()才会启动 |
~QThread() |
破坏QThread。 注意:删除QThread将会stop线程的执行。删除一个运行中QThread将会导致程序碰撞。删除QThread前应该先等待finished()信号。 |
3、静态字段
enum | Priority |
{ IdlePriority, LowestPriority, LowPriority, NormalPriority, HighPriority, …, InheritPriority } |
线程优先级 |
Constant | Value | Description |
---|---|---|
QThread::IdlePriority |
0 |
scheduled only when no other threads are running. |
QThread::LowestPriority |
1 |
scheduled less often than LowPriority. |
QThread::LowPriority |
2 |
scheduled less often than NormalPriority. |
QThread::NormalPriority |
3 |
the default priority of the operating system. |
QThread::HighPriority |
4 |
scheduled more often than NormalPriority. |
QThread::HighestPriority |
5 |
scheduled more often than HighPriority. |
QThread::TimeCriticalPriority |
6 |
scheduled as often as possible. |
QThread::InheritPriority |
7 |
use the same priority as the creating thread. This is the default. |
4、静态方法
返回值类型 |
方法 |
说明 |
QThread * |
create(Function &&f, Args &&... args) create(Function &&f) |
构造一个新的QThread,该线程将执行函数f,后边的参数是函数f的参数。 该线程并没有启动——必须直接通过start()才能启动。这允许我们连接它们的信号、把某些QObject转移到Thread中、确定优先级等。 支持参数的create方法只有在使用C++17时才能用。 不要多次在QThread中调用start() |
QThread * | currentThread() | 返回当前执行的线程 |
Qt::HANDLE | currentThreadId() | 返回当前执行的线程的Handle |
int | idealThreadCount() | 返回系统中能运行的线程的最大数量。 |
void | sleep(unsigned long secs) | 休眠若干秒 |
void | msleep(unsigned long msecs) | 休眠若干毫秒 |
void | usleep(unsigned long usecs) | 休眠若干微秒 |
void | yieldCurrentThread() |
5、实例方法
返回值类型 |
方法 |
说明 |
QAbstractEventDispatcher * | eventDispatcher() | 指向该线程的Event Dispatcher。如果不存在时则返回nullptr。 |
protected int | exec() |
进入事件循环,直至调用exit(),返回传递给exit()的值。如果通过quit()调用exit()则返回0。 该方法内部将会执行run(),调用该方法来启动一个消息循环。 该方法只能被当前线程调用。 |
void | exit(int returnCode = 0) |
使线程的事件循环终止并返回一个returnCode。 0代表成功,非0代表失败。 |
bool | 如果线程完成时,返回true | |
如果在该线程中运行的任务需要被终止,返回true | ||
当线程正在运行时,返回true | ||
int | loopLevel() | 返回当前线程的事件循环等级。 |
QThread::Priority | priority() | 返回当前线程优先级。 |
void | requestInterruption() | 请求线程的中止。 |
void |
setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) setPriority(QThread::Priority priority) setStackSize(uint stackSize) |
设置EventDispatched、优先级、栈大小。 |
uint | stackSize() | 返回当前线程的栈大小 |
bool |
wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever)) wait(unsigned long time) |
1、阻塞当前线程直到以下情况发生: ①该QThread相关的Thread完成执行;此时返回true ②deadline时间到了;此时返回false 2、等待若干秒 |
6、槽
quit() |
使线程的事件循环退出,返回0(成功时)。等同于调用QThread::exit(0)。 如果不存在消息循环,该方法将什么都不做。 |
start(QThread::Priority priority = InheritPriority) | 通过调用run()来运行该线程。OS将根据参数priority来调度线程。如果线程已经在运行了,那么该方法讲什么都不做。 |
terminate() | 终止线程运行,不推荐。 |
7、信号
finished() |
线程正要完成执行前发送该信号。 发送该信号之后,事件循环就停止了,不会有更多事件在线程中运行了,除非一些推迟的资源回收、删除事件。 该事件常与QObject::deleteLater()连接,用于释放线程中的资源。 注意:如果通过terminate()来终止进程,那么就不能确定该信号是被哪个线程发送了。 |
started() | 当线程开始执行时发送该信号,在run()方法调用前。 |
Qt:QThread的更多相关文章
- Qt之QThread(深入理解)
简述 为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程.对于耗时操作如果不使用线程,UI界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用线程来解决这个问题. 前面,已 ...
- 解析Qt中QThread使用方法
本文讲述的是在Qt中QThread使用方法,QThread似乎是很难的一个东西,特别是信号和槽,有非常多的人(尽管使用者本人往往不知道)在用不恰当(甚至错误)的方式在使用QThread,随便用goog ...
- Qt线程QThread简析(8个线程等级,在UI线程里可调用thread->wait()等待线程结束,exit()可直接退出线程,setStackSize设置线程堆栈,首次见到Qt::HANDLE,QThreadData和QThreadPrivate)
QThread实例代表一个线程,我们可以重新实现QThread::run(),要新建一个线程,我们应该先继承QThread并重新实现run()函数. 需要注意的是: 1.必须在创建QThread对象之 ...
- Qt线程—QThread的使用--run和movetoThread的用法
Qt使用线程主要有两种方法: 方法一:继承QThread,重写run()的方法 QThread是一个非常便利的跨平台的对平台原生线程的抽象.启动一个线程是很简单的.让我们看一个简短的代码:生成一个在线 ...
- Qt多线程-QThread
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QThread 本文地址:http://techieliang.com/2 ...
- 重点:怎样正确的使用QThread类(很多详细例子的对比,注意:QThread 中所有实现的函数是被创建它的线程来调用的,不是在线程中)good
背景描述: 以前,继承 QThread 重新实现 run() 函数是使用 QThread唯一推荐的使用方法.这是相当直观和易于使用的.但是在工作线程中使用槽机制和Qt事件循环时,一些用户使用错了.Qt ...
- 【QT】 QThread部分源码浅析
本文章挑出QThread源码中部分重点代码来说明QThread启动到结束的过程是怎么调度的.其次因为到了Qt4.4版本,Qt的多线程就有所变化,所以本章会以Qt4.0.1和Qt5.6.2版本的源码来进 ...
- 【QT】QThread源码浅析
本章会挑出QThread源码中部分重点代码来说明QThread启动到结束的过程是怎么调度的.其次因为到了Qt4.4版本,Qt的多线程就有所变化,所以本章会以Qt4.0.1和Qt5.6.2版本的源码来进 ...
- Qt:禁止qDebug的输出
Qt:禁止qDebug的输出 在工程的.pro文件里加上以下编译批令即可: DEFINES += QT_NO_DEBUG_OUTPUT
随机推荐
- Apple历代Mac系统汇总
编号 系统名 版本号 名称 发布时间 01 macOS 11.0 Big Sur(大惊喜) 2020年6月 02 macOS 10.15 Catalina(卡特琳娜) 2019年9月 03 macOS ...
- echarts图表的封装
其实echarts官网有个快速上手的教程,一般人看一遍也知道是怎么回事,先给个传送门吧--五分钟上手 引入方式多种多样就自己去官网看了--这里简单介绍echarts怎么用,下方的封装函数比较重要 1. ...
- <select><option></option></select> 操作
转载请注明来源:https://www.cnblogs.com/hookjc/ function FlySwapSelect(s1,s2,myvars,calldbclick){ var mSel1= ...
- [01-jwt]C# JWT基础知识详解
本篇文章将介绍jwt基础概念性知识,不含实操代码展示,特别适合该方面知识空白的人群,大神级别请选择性观看.不喜禁喷,出门右转,谢谢配合. 一.什么是JWT? JWT是简写,全称是JSON Web To ...
- 【ASP.NET Core】设置 Web API 响应数据的格式——FormatFilter特性篇
在上一篇烂文中老周已向各位介绍过 Produces 特性的使用,本文老周将介绍另一个特性类:FormatFilterAttribute. 这个特性算得上是筛选器的马甲,除了从 Attribute 类派 ...
- 【密码学工具】Ciphey和WinDecrypto的使用随笔
1.Ciphey 官方文档 这个工具安装起来也很容易,用pip下载即可. pip install ciphey -i https://pypi.mirrors.ustc.edu.cn/simple/ ...
- Solution -「多校联训」博弈
\(\mathcal{Description}\) Link. A B 两人在树上博弈,初始时有一枚棋子在结点 \(1\).由 A 先操作,两人轮流移动沿树上路径棋子,且满足本次移动的树上距离 ...
- Solution -「ARC 082D」Sandglass
\(\mathcal{Description}\) Link. 一个沙漏内共 \(Xg\) 沙,令初始时上半部分为 A,下半部分为 B.沙漏在 \(r_1,r_2,\cdots,r_n\) 时 ...
- verification TLM传输数据导致多线程访问同一个数据
TLM传输数据导致多线程访问同一个数据 原因 TLM发送数据跟mailbox类似,都是发送的引用,这样发送端和接收端的引用都指向同一个数据,这样就会出现发送端修改数据会影响到接收端,比如发送的时候数据 ...
- MyBatis封装JDBC具体实现
关于xml等解析的工具基本均包含在org.apache.ibatis.builder包中,有包名可知基本使用建造者模式.这个包的主要功能两个: 1.解析XML配置文件和映射文件,xml子包中: 2.解 ...