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
随机推荐
- Mysql-5.7主从部署-yum方式
一.环境准备 # rpm -qa |grep mariadb |xargs yum remove -y # setenforce 0(临时关闭),(selinux配置文件:SELINUX=disabl ...
- C++函数调用过程解析
编译环境:Windows 10 + VS2015. 0.引言 函数调用的过程实际上也就是一个中断的过程,本文演示和深入分析参数入栈.函数跳转.保护现场.恢复现场等函数调用过程. 首先对三个常用的寄存器 ...
- NumPy 教程目录
NumPy 教程目录 1 Lesson1--NumPy NumPy 安装 2 Lesson2--NumPy Ndarray 对象 3 Lesson3--NumPy 数据类型 4 Lesson4--Nu ...
- 理解java线程的中断(interrupt)
一个线程在未正常结束之前, 被强制终止是很危险的事情. 因为它可能带来完全预料不到的严重后果比如会带着自己所持有的锁而永远的休眠,迟迟不归还锁等. 所以你看到Thread.suspend, Threa ...
- IDEA:修改JAVA文件自动引入import.*包
感谢大佬:https://blog.csdn.net/fly910905/article/details/90208744 问题描述 Intellij Idea工具在java文件中,经常会自动导入im ...
- 实例15_C语言绘制万年历
实例说明:
- Typora如何上传图片到gitee
Typora是一款非常好用的Markdown文本编辑器,深受广大程序员的青睐,那么在使用过程中,当我们插入图片的时候,其实是默认放在一个相对路径文件夹下的,这就导致,一旦我们移动文件,或者发送给别人, ...
- python基础语法_python中的布尔类型详解
转自:http://www.cnblogs.com/521yywzyzhc/p/6264885.html 我们已经了解了Python支持布尔类型的数据,布尔类型只有True和False两种值,但是 ...
- windows server2012搭建邮箱服务器+客户端界面(hmailserver+afterlogic)+批量创建邮箱
1.简介 由于需要较多邮箱,如果去注册需要很多的手机号码去验证,一个人不可能买一堆的手机号,所以自己搭建一个邮箱服务器可以大批量的创建自己的邮箱账号和收发邮件. 2.安装部署hmailserver 下 ...
- 基于ASP.NET Core 5.0使用RabbitMQ消息队列实现事件总线(EventBus)
文章阅读请前先参考看一下 https://www.cnblogs.com/hudean/p/13858285.html 安装RabbitMQ消息队列软件与了解C#中如何使用RabbitMQ 和 htt ...