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、信号
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性