闲谈
前几篇,说了Qt线程的最常见的QThread和偷懒的QtConcurrent,这两者使用的场景是不同的,前者更具有交互型,后者独立。对于QtConcurrent这种高级API如何让他发挥极致呢,我们就要用到QThreadPool和完美的QEventLoop,当然C++11就是最强搭档。在实践中,再次体会到Qt的事件驱动框架,以及信号和槽。可以这样说:谈及Qt的线程,线程工作与卡槽中。本篇是看自Jason大神的开源项目,特别感谢,送个小星星,实在优秀,还在学习中。对于其使用场景等目前水平不涉及,再次略记一笔。
备战
- 首先,对于std::function,这样一个一统天下的大将军打开了函数之间交流的道路,想去那就去那,参数。
- QEventLoop,这样的护国法师使得帝国青山常在,生命。
- QtConcurrent,可谓开国领袖,为我们撑起一片天,创建线程。
- QThreadPool,好比矿产资源,线程管理者。
实战
#define MAX_COUNT 10
// 线程池
threadPool = QSharedPointer<QThreadPool>(new QThreadPool);
threadPool->setMaxThreadCount(MAX_COUNT);
// 事件循环
eventloops = QSharedPointer<QVector<QPointer<QEventLoop>>>(new QVector<QPointer<QEventLoop>>);
eventloops->resize(MAX_COUNT);
// 工作者
workers = QSharedPointer<QVector<QPointer<WorkerHelp>>>(new QVector<QPointer<WorkerHelp>>);
workers->reserve(MAX_COUNT);
// 线程
for(auto one = 0; one < MAX_COUNT; one++){
auto funObj = [this](int index){
qDebug() << "thread poor"<< index <<"id:" << QThread::currentThreadId();
// 线程死循环
QEventLoop loop;
WorkerHelp woker;
eventloops->append(&loop);
workers->append(&woker);
loop.exec();
};
// high-api
QtConcurrent::run(threadPool.data(), funObj, one);
}
如上,我们创建一个拥有10个线程的线程池,并开启每个线程,且每个线程都有一个事件循环和工作者。使用时,分配任意一个工作者任务即可。工作者如下:
class WorkerHelp : public QObject
{
Q_OBJECT
public:
explicit WorkerHelp(QObject *parent = nullptr);
// 获取要执行的任务
void startTask(const std::function<void()> &_task);
// or slots
public Q_SLOTS:
// 卡槽中执行
void working();
private:
std::function<void()> task = nullptr;
};
WorkerHelp::WorkerHelp(QObject *parent)
:QObject(parent){}
void WorkerHelp::startTask(const std::function<void ()> &_task)
{
task = _task;
// sig-slot
QMetaObject::invokeMethod(
this,
"working",
Qt::QueuedConnection
);
}
void WorkerHelp::working()
{
task();
}
使用如下
// 使用 lambda ,std::function 函数高度自由
workers->at(index)->startTask([a,b,c,....](){
// task content
});
线程终止,因为我们对每个线程开启事件循环,所以通过sig-slot通知loop-quit即可,如下
// 线程quit 通过信号和槽
for(auto &one : *eventloops){
QMetaObject::invokeMethod( one.data(), "quit" );
}
threadPool->waitForDone();
本篇仍需更改,待续。