QThreadPool
详细描述
QThreadPool管理和回收单个QThread对象,以帮助减少程序中线程的创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()
来访问该对象。
要使用一个QThreadPool线程,请子类QRunnable并实现run()
虚拟函数。然后创建该类的对象,并将其传递给QThreadPool::start()
。
#include "widget.h"
#include <QApplication>
#include <QDebug>
#include <QRunnable>
#include <QThread>
#include <QThreadPool>
class HelloWorldTask : public QRunnable {
public:
HelloWorldTask(int i)
{
idx = i;
}
protected:
void run() override
{
Qt::HANDLE pid = QThread::currentThread()->currentThreadId();
qDebug() << idx << ": Hello world from thread" << pid;
}
int idx;
};
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
for (int i = 0; i < 10; i++) {
// QThreadPool获取所有权并自动删除'hello'
HelloWorldTask* hello = new HelloWorldTask(i);
QThreadPool::globalInstance()->start(hello);
}
return a.exec();
}
QThreadPool支持通过在QRunnable::run()
中调用tryStart(this)
来多次执行同一个QRunnable。如果autoDelete被启用,QRunnable将在最后一个线程退出run函数时被删除。当autoDelete启用时,使用相同的QRunnable多次调用start()
会创建一个竞争条件,不建议这样做。
在一定时间内未使用的线程将过期。默认超时时间为30000毫秒(30秒)。这可以使用setExpiryTimeout()
来更改。设置负超时时间将禁用过期机制。
调用maxThreadCount()
查询要使用的最大线程数。如果需要,可以使用setMaxThreadCount()
来更改这个限制。默认的maxThreadCount()
是QThread::idealThreadCount()
。函数的作用是:返回当前执行工作的线程数。
reserveThread()
函数保留一个线程供外部使用。 处理完线程后,请使用releaseThread()
,以便可以重用它。本质上,这些函数会暂时增加或减少活动线程数,并且在实现QThreadPool不可见的耗时操作时非常有用。
请注意,QThreadPool是用于管理线程的低级类,有关更高级的选择,请参阅Qt Concurrent模块。
属性文档
activeThreadCount : const int
此属性表示线程池中活动线程的数量。
注意:此函数有可能返回大于
maxThreadCount()
的值。有关更多详细信息,请参见reserveThread()
。
expiryTimeout : int
在expiryTimeout毫秒内未使用的线程将被视为已过期并将退出。 此类线程将根据需要重新启动。 默认的expiryTimeout为30000毫秒(30秒)。 如果expiryTimeout为负数,则新创建的线程将不会过期,例如,直到销毁线程池后,它们才会退出。
请注意,设置expiryTimeout对已经运行的线程无效。 仅新创建的线程将使用新的expiryTimeout。 我们建议在创建线程池之后调用**start()**
之前立即设置expiryTimeout。
maxThreadCount : int
此属性表示线程池使用的最大线程数。
注意:即使maxThreadCount限制为零或负数,线程池将始终至少使用1个线程。
默认的maxThreadCount是
QThread::idealThreadCount()
。
stackSize : uint
此属性包含线程池工作线程的堆栈大小。
该属性的值仅在线程池创建新线程时使用,更改它对已创建或正在运行的线程无效。
默认值为0,这使QThread使用操作系统的默认堆栈大小。
成员函数文档
QThreadPool::QThreadPool(QObject *parent = nullptr)
用给定的父线程构造一个线程池。
QThreadPool::~QThreadPool()
销毁QThreadPool。该功能将阻塞,直到所有可运行对象都已完成。
void QThreadPool::clear()
从队列中删除尚未启动的可运行对象。runnable->autoDelete()
返回true的runnable将被删除。
bool QThreadPool::contains(const QThread *thread) const
如果thread是由该线程池管理的线程,则返回true。
注:Qt6.0 开始才有该API
QThreadPool *QThreadPool::globalInstance()
返回全局QThreadPool实例。
void QThreadPool::releaseThread()
释放之前通过调用reserveThread()
保留的线程。
注意:在没有预先保留线程的情况下调用这个函数会临时增加
maxThreadCount()
。当一个线程进入睡眠状态以等待更多的工作时,这很有用,从而允许其他线程继续。确保在完成等待时调用reserveThread()
,以便线程池能够正确地维护activeThreadCount()
。
void QThreadPool::start(QRunnable *runnable, int priority = 0)
保留一个线程并使用它运行runnable,除非该线程将使当前线程数超过maxThreadCount()。在这种情况下,runnable会被添加到运行队列中。priority参数可用于控制运行队列的执行顺序。
请注意,如果
runnable->autoDelete()
返回true,则线程池将获得runnable的所有权,并且在runnable->run()
返回之后,线程池将自动删除该runnable。 如果runnable->autoDelete()
返回false,则调用者将保留runnable的所有权。请注意,在调用此函数后更改runnable的自动删除将导致未定义的行为。
void QThreadPool::start(std::function
这是一个重载函数。
保留一个线程并使用它运行functionToRun,除非该线程使当前线程数超过maxThreadCount()
。 在这种情况下,functionToRun被添加到运行队列代替。 priority参数可用于控制运行队列的执行顺序。
bool QThreadPool::tryStart(QRunnable *runnable)
尝试保留一个线程来运行runnable。
如果在调用时没有线程可用,则此函数不执行任何操作并返回false。否则,将使用一个可用线程立即运行runnable,并且此函数返回true。
请注意,如果
runnable->autoDelete()
返回true,则线程池成功获取runnable的所有权,并且在runnable->run()
返回之后,线程池将自动删除该runnable。 如果runnable->autoDelete()
返回false,则调用者将保留runnable的所有权。 请注意,在调用此函数后更改runnable的自动删除将导致未定义的行为。
bool QThreadPool::tryStart(std::function
这是一个重载函数。
尝试保留线程以运行functionToRun。
如果在调用时没有线程可用,则此函数不执行任何操作并返回false。 否则,functionToRun将使用一个可用线程立即运行,并且此函数返回true。
bool QThreadPool::tryTake(QRunnable *runnable)
尝试从队列中删除指定的可运行对象(如果尚未启动)。 如果runnable尚未启动,则返回true,并且runnable的所有权会转移到调用方(即使runnable->autoDelete() == true
)。 否则返回false。
注意:如果runnable->autoDelete() == true
,则此函数可能会删除错误的runnable。 这被称为ABA问题:原始的可运行对象可能已经执行,并已被删除。 内存被另一个可运行程序重用,然后被删除,而不是删除预期的。 因此,我们建议仅对未自动删除的可运行对象调用此函数。
bool QThreadPool::waitForDone(int msecs = -1)
等待msecs毫秒退出(以毫秒为单位),然后从线程池中删除所有线程。 如果所有线程都被删除,则返回true; 否则返回false。 如果毫秒为-1(默认值),则忽略超时(等待最后一个线程退出)。
QRunable
详细描述
QRunnable类是一个接口,用于表示需要执行的任务或代码,通过重新实现run()
函数来表示。
可以使用QThreadPool在单独的线程中执行代码。 如果autoDelete()
返回true(默认值),则QThreadPool会自动删除QRunnable。 使用setAutoDelete()
更改自动删除标志。
QThreadPool通过在run()函数中调用QThreadPool::tryStart(this)
支持多次执行同一QRunnable。 如果启用了autoDelete,则当最后一个线程退出运行功能时,QRunnable将被删除。 启用autoDelete时,使用相同的QRunnable多次调用QThreadPool::start()
会创建竞争条件,建议不要这样做。
成员函数文档
QRunnable::QRunnable()
构造一个QRunnable。默认启用“自动删除”。
QRunnable::~QRunnable()
QRunnable的析构函数。
bool QRunnable::autoDelete() const
如果启用了自动删除,则返回true;否则,返回false。 否则为假。
如果启用了自动删除,则QThreadPool将在调用run()之后自动删除此可运行对象。 否则,所有权仍然属于应用程序程序员。
QRunnable *QRunnable::create(std::function
创建一个在run()中调用functionToRun的QRunnable。
默认情况下启用自动删除。
void QRunnable::run()
在你的子类中实现这个纯虚函数。
void QRunnable::setAutoDelete(bool autoDelete)
如果autoDelete为true,则启用自动删除。 否则将禁用自动删除。
如果启用了自动删除,则QThreadPool将在调用run()之后自动删除此可运行对象。 否则,所有权仍然属于应用程序程序员。
请注意,必须在调用
QThreadPool::start()
之前设置此标志。在QThreadPool::start()
之后调用此函数将导致未定义的行为。