Qt多线程 — QThreadPool 线程池
一、简介
ThreadPool
用于管理和回收单个QThread对象,目的是减少使用线程的应用程序中的创建线程的成本。每个Qt应用程序都包含一个全局的QThreadPool
对象,可以调用globalInstance()来访问这个全局的QThreadPool
对象。
二、使用方法
使用QThreadPool线程,需按照以下4个步骤:
(1)继承QRunnable。
(2)重载并实现run()
虚函数。
(3)创建该类的一个对象。
(4)将创建的对象传递给QThreadPool::start()。
例如以下代码片段:
//【1】继承QRunnable,定义MyTask类
class MyTask : public QRunnable
{
//【2】重载并实现run()虚函数
void run() override
{
qDebug() << "I'm iriczhao!!!" << QThread::currentThread();
}
};
//【3】创建MyTask类的对象my_task
MyTask *my_task = new MyTask();
//【4】将创建的对象传递给QThreadPool::start
QThreadPool::globalInstance()->start(my_task);
三、QThreadPool的成员函数
(3-1)设置自动删除标志【setAutoDelete】
默认情况下,QThreadPool会自动删除QRunnable。使用QRunnable::setAutoDelete()
来更改自动删除标志。
注意:这个标志必须在调用QThreadPool::start()之前设置。在QThreadPool::start()之后调用setAutoDelete
函数将出现未定义的行为。
QThreadPool支持在QRunnable::run()中调用tryStart(this)来多次执行同一个QRunnable。如果autoDelete被启用,QRunnable将在最后一个线程退出run函数时被删除。在启用autoDelete
条件下,使用同一个QRunnable对象多次调用start()会创建一个竞争条件(在开发中不建议这样使用)。
(3-2)设置线程超时时间【setExpiryTimeout】
在一定时间内未使用的线程将过期(超时时间为30000毫秒(30秒)),Qt中使用expiryTimeout来描述该参数。这个参数可以使用setExpiryTimeout()
函数更改。当超时时间设置为负数时将禁用线程过期机制。
在expiryTimeout毫秒内未使用的线程被认为已经过期并将退出。这些线程将在需要时再重新启动。默认的expiryTimeout是30000毫秒(30秒)。如果expiryTimeout为负值,则新创建的线程不会过期,例如:在线程池销毁之前,线程不会退出。
(3-3)设置线程池的最大线程数【setMaxThreadCount】
- 调用
maxThreadCount()
来查询线程池中使用的最大线程数。 - 可以使用setMaxThreadCount()更改最大的线程数。默认maxThreadCount()是
QThread::idealThreadCount()
函数的结果。 - 使用
activeThreadCount()
函数返回当前正在运行的线程数。注:该函数的返回值可能会大于最大线程数maxThreadCount
(3-4)预留线程【reserveThread】
调用reserveThread()
函数预留一个线程。如果一个线程运行完成,则可以调用releaseThread()
允许它被重用。注意:这个函数会增加活动线程的数量。
void QThreadPool::reserveThread()
(3-5)释放线程【releaseThrad】
releaseThread()
函数的作用是:释放使用reserveThread()
预留的线程。
注意:如果调用此函数时,没有预先预留线程,则会临时增加maxThreadCount()。当一个线程进入休眠状态,等待更多工作时,此时使用该函数很有用,因为它允许其他线程继续工作。在使用中,需确保在完成等待后再调用reserveThread()
,以便线程池能够正确维护活动线程的数量。
void QThreadPool::releaseThread()
(3-6)开始线程【start】
开始线程池运行调度,在这种情况下,runnable被添加到运行队列中。priority参数可以用来控制运行队列的执行顺序。
void QThreadPool::start(QRunnable *runnable, int priority = 0)
在Qt5.15版本后,支持运行一个函数:
void QThreadPool::start(std::function<void ()> functionToRun, int priority = 0)
(3-7)设置堆栈大小【setStackSize】
该属性值仅在线程池创建新线程时使用。更改它对已经创建或正在运行的线程没有影响。默认值是0,这使得QThread使用操作系统的默认堆栈大小。
(3-8)清除线程池【clear】
从队列中移除尚未启动的runnable
。如果runnable->autoDelete()返回true,则runnable将被删除。
void QThreadPool::clear()
(3-9)等待执行完成【waitForDone】
使用waitForDone
设置线程超时等待时间。如果所有线程都被移除,则返回true;否则返回false。如果msecs为-1(默认值),则忽略超时(等待最后一个线程退出)。
bool QThreadPool::waitForDone(int msecs = -1)
四、使用示例
(4-1)定义runnable
在以下代码中,将定义三个运行线程:MyTask0
、MyTask1
、MyTask2
class MyTask0 :public QRunnable
{
public:
MyTask0(){}
~MyTask0()override
{
qDebug()<<"MyTask0 exit!!";
}
protected:
void run() override
{
qDebug() << "MyTask0" << QThread::currentThread();
}
};
class MyTask1 :public QRunnable
{
public:
MyTask1(){}
~MyTask1()override
{
qDebug()<<"MyTask1 exit!!";
}
protected:
void run() override
{
qDebug() << "MyTask1"<< QThread::currentThread();
}
};
class MyTask2 :public QRunnable
{
public:
MyTask2(){}
~MyTask2()override
{
qDebug()<<"MyTask2 exit!!";
}
protected:
void run() override
{
qDebug() << "MyTask2" << QThread::currentThread();
}
};
(4-2)main函数
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//创建任务
auto *Task0 = new MyTask0();
auto *Task1 = new MyTask1();
auto *Task2 = new MyTask2();
//开始Task0
QThreadPool::globalInstance()->start(Task0);
QThreadPool::globalInstance()->waitForDone(-1);
//开始Task1
QThreadPool::globalInstance()->start(Task1);
QThreadPool::globalInstance()->waitForDone(-1);
//开始Task2
QThreadPool::globalInstance()->start(Task2);
QThreadPool::globalInstance()->waitForDone(-1);
qDebug()<<"activeThreadCount"<<QThreadPool::globalInstance()->activeThreadCount()<<"maxThreadCount" <<QThreadPool::globalInstance()->maxThreadCount();
return 0;
}
【输出结果】
MyTask0 QThreadPoolThread(0x312f3d0, name = "Thread (pooled)")
MyTask0 exit!!
MyTask1 QThreadPoolThread(0x312f5f0, name = "Thread (pooled)")
MyTask1 exit!!
MyTask2 QThreadPoolThread(0x312f510, name = "Thread (pooled)")
MyTask2 exit!!
activeThreadCount 0 maxThreadCount 8
扫一扫关注微信公众号,获取更多精彩内容>>>>