在QT中创建一个线程的方法有很多,与std::thread最为接近的是QtConcurrent。QT中有四个创建线程的方法分别是:
-
继承QThread对象
-
moveToThread方法
-
QRunnable方法
-
QtConcurrent::run方法
下面是对各种方法的优缺点总结:
方法用法注意事项优点缺点继承QThread
首先,创建一个继承自 QThread
的类并对其 run
方法进行重写。接着,实例化这个类并用 start
方法启动线程。当run()
方法执行完毕,线程会自动结束。不建议在派生的QThread
类中使用槽。提供了完整的线程管理功能和与其他线程的通信功能需要手动继承和重写方法,处理线程的生命周期可能有挑战,例如正确地回收线程资源QObject::moveToThread
首先实例化一个QObject
对象和一个QThread
对象。然后QObject
的moveToThread()
方法来将QObject
(及其任何子对象)从它当前的线程上下文移动到与QThread
实例关联的线程1. 确保移动的时候不要被其他线程使用 2.QObject
及其所有子对象必须始终位于同一个线程提供了线程间通信的方便,移动对象到线程比继承QThread
更灵活、更简单虽然比继承QThread
简单,但仍需要注意线程生命周期的管理,确保正确地回收资源继承QRunnable
创建一个继承QRunnable
的类并重写run方法,然后通过QThreadPool
启动默认情况下,QRunnable
对象的autoDelete属性被设置为true
,这意味着一旦任务完成,它会被自动删除。可以轻松与线程池结合使用,自动管理线程资源,可以多次启动相同的任务与QThread
相比,为了进行通信,你可能需要使用其他手段如信号和槽或其他机制QtConcurrent::run
调用QtConcurrent::run
函数,传入一个函数、lambda
或其他可调用对象,以并发方式执行如果线程池满,提交的任务可能会延迟执行,直到线程池中有可用线程使用极其简单,能与QFuture
结合以获得异步结果,无需手动管理线程生命周期对于复杂的线程间通信和同步可能不够灵活,线程池满时可能无法立即执行任务
为了方便使用Qt的信号与槽机制,我们常常采用表格的前两种方法,即继承QThread或者使用moveToThreafd方法;如果你没有用到信号与槽,那么你完全可以采用std::thread或者QtConcurrent::run方法。 为了支持信号与槽的机制,我们通常会使用前两种方法,也就是重写run或者moveToThread。moveToThread的优点在于你可以让这个继承QThread类的所有槽都运行在新线程内,而
本文讲述的是使用QThread进行管理线程创建方法,也就是上述表格的前两个。在使用之前首先需要对QThread的类有一定的理解:
一、QThread管理QThread类是QT提供的一个与平台无关的管理线程的类。一个QThread对象管理一个程序中的线程,run函数是实际执行的内容。默认情况下,run将会通过的调用exec()来启动事件循环并在线程内启动事件循环。
在介绍这个方法之前有必要对QThread
对象做个简单的介绍。以下内容属于搬运[1]:
void quit();//Equivalent to calling QThread::exit(0)
void start(QThread::Priority priority = InheritPriority);
void terminate();
quit() 停止线程的事件循环。如果线程没有事件循环等于什么都不做。
start() 开启线程。开启线程将会调用run()方法,操作系统将会根据优先级安排线程的执行,如果一个线程已经被运行,那么槽函数将不会做任何事情。
terminate() 终止一个线程。线程不一定会立刻终止,这取决于操作系统的调度策略,在调用terminate()后使用QThread::wait() ,wait()函数和POSIX的 pthread_join() 功能是一样的。不推荐使用,因为线程的资源可能因为你的强制终止而永远得不到释放。
1.2 信号void finished();
void started();
finished() 如果相关线程完成了执行将会发出此信号。这意味着事件循环将只剩下延迟删除的事件。注意,如果你调用terminate()是否会发出这个信号是不一定的,他是一个内部信号。
started() 相关线程在run()函数被调用之前将发出此信号。
1.3 受保护的函数int exec();
virtual void run();
exec()调用将使得线程进入事件循环并等到exit()被调用,返回值是传递给exit的数值,如果返回值是0,说明是调用quit退出的。我们一般不需要手动执行exec()的原因是因为run()默认实现会调用exec。
run()是线程的入口,当线程对象调用start()新创建的线程将会调用该函数。默认情况run()函数实现将会只调用exe函数,重新实现run函数以便定制高级的线程管理,该函数返回线程将会停止执行。
1.4 其他重要公共函数void exit(int returnCode=0);
bool wait(unsigned long time = ULONG_MAX);
void setPriority(QThread::Priority priority)
exit()停止事件循环,在QEventLoop::exec()执行后返回,返回值将是退出码。0表示正常退出,非零表示有错误。事件循环将会停止,直至再次调用QThread::exec()。
wait() 将会阻塞线程至满足下面两个条件的其中一个:
- 线程执行完毕。run()返回或者线程尚未开始
- 定时结束。默认是永远不会返回,也就是只能是顶一个,当然你设置了超时时间,那么将会返回一个false并结束阻塞。
下面是状态指示:
bool isFinished();
bool isRunning()const;
下面这个是用来优雅退出一个线程的方法:
bool isInterruptionRequested()const;
void requestInterruption();
具体用法参照这里。
1.5 重要静态方法void sleep(unsigned long secs);
void msleep(unsigned long msecs);
void usleep(unsigned long usecs);
int QThread::idealThreadCount()
返回 idealThreadCount()当前处理器的最佳线程数。
二、继承QThread方法#include
#include
#include
class MyThread:public QThread{
protected:
void run() override;
};
void MyThread::run()
{
int i=0;
for(int j=0;j
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?