这一篇主要设计了业务线程的管理,我设计的业务线程分两种,一种是单次执行,执行完了就释放;每当有新任务时,就新建一个,然后用线程池来启动,如果当前没有空闲线程,它会等到有空闲线程时,再执行这个任务;执行完了之后会自动释放。由于这种单次执行比较灵活,只是在用到的地方新建、然后启动就可以了,当有消息时会用信号通知,出不用管理释放,所以我没有对这种类型进行管理。下面介绍死循环线程的管理。
首先声明接口
#ifndef WORKMANAGERAPI_H
#define WORKMANAGERAPI_H
#include <QObject>
class QThreadPool;
class QVariant;
namespace BLL {
class Worker;
class WorkerManager : public QObject
{
Q_OBJECT
public:
WorkerManager(QThreadPool *thrPool,QObject *parent = nullptr): _thrPool(thrPool), QObject(parent) {}
virtual void installWorker(std::string name, Worker * w) = 0; //通过名字,标识Worker
virtual Worker* getWorker(std::string name) = 0; //用名字来访问Worker
Q_INVOKABLE virtual void startWorker(Worker*w, int threadCount = 1) = 0; //Worker启动多少个线程
virtual QThreadPool* threadPool() const {return _thrPool;} //当前线程池对象
private:
QThreadPool *_thrPool = nullptr;
};
}
#endif // WORKMANAGERAPI_H
然后是其中一个实现
#ifndef BASEWORKERMANAGER_H
#define BASEWORKERMANAGER_H
#include "workmanagerapi.h"
namespace BLL {
class BaseWorkerManager : public WorkerManager
{
Q_OBJECT
public:
BaseWorkerManager(QThreadPool *thrPool, QObject*parent = nullptr) : WorkerManager(thrPool,parent){}
~BaseWorkerManager();
void installWorker(std::string name,Worker * w) override;
Worker* getWorker(std::string name) override;
void startWorker(Worker*w, int threadCount = 1) override;
private:
std::map<std::string,Worker*> _workerMap;
std::map<Worker*,int> _workerThreadCountMap;
bool _firstFlag = true;
};
}
#endif // BASEWORKERMANAGER_H
#include "baseworkermanager.h"
#include "workerapi.h"
#include <QThreadPool>
#include <QDebug>
BLL::BaseWorkerManager::~BaseWorkerManager()
{
for(auto p : _workerThreadCountMap){
for(int i = 0; i < p.second; i++){
p.first->quit(); //依次往Worker中的每一个子线程推一个退出任务,使其退出
}
}
}
//只处理死循环类型的Worker
void BLL::BaseWorkerManager::installWorker(std::string name, BLL::Worker *w)
{
if(w->workerType() == RunOnce){
return;
}
_workerMap[name] = w;
}
//通过名字来访问
BLL::Worker *BLL::BaseWorkerManager::getWorker(std::string name)
{
auto iter = _workerMap.find(name);
if(iter == _workerMap.end()){
return nullptr;
}
return iter->second;
}
//启动Worker,可以启动单次运行的
void BLL::BaseWorkerManager::startWorker(BLL::Worker *w, int threadCount)
{
if(w->workerType() == RunOnce){
for(int i = 0; i < threadCount; i++){
threadPool()->start(w);
}
}else if(w->workerType() == RunForever){
if(_firstFlag){//只启动一次
int havCount = threadPool()->maxThreadCount() - threadPool()->activeThreadCount();//以当前可用线程数量来限定启动数量
if(havCount < threadCount){
qDebug() << "have no enough thread count to start alawys worker,but started" << havCount << "worker";
threadCount = havCount;
}
for(int i = 0; i < threadCount; i++){
threadPool()->start(w);
}
_workerThreadCountMap[w] = threadCount;
_firstFlag = false;
}else{
qDebug() << "alawys run thread count had been started";
}
}
}
下面就是在主线程中的使用了
#include <QGuiApplication>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include "BLL/runforeverworker.h"
#include "BLL/runoneceworker.h"
#include "BLL/core/baseworkermanager.h"
#include <QThreadPool>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<BLL::RunForeverWorker>("MyModel",1,0,"RunForever");
BLL::BaseWorkerManager *workerManager = new BLL::BaseWorkerManager(QThreadPool::globalInstance());
BLL::RunForeverWorker *foreverWorker = new BLL::RunForeverWorker;
workerManager->installWorker("RunForever",foreverWorker);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("worker",foreverWorker);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
workerManager->startWorker(foreverWorker,2);
BLL::RunOneceWorker *onceWorker = new BLL::RunOneceWorker;
onceWorker->requestData();
workerManager->startWorker(onceWorker);
QObject::connect(&app,&QGuiApplication::lastWindowClosed,[workerManager]{
workerManager->deleteLater();
});
return app.exec();
}
这个应用是qml应用,由于qml应用对象全局可见就没用必要再设计。如果是Widget的话,需要把Widget和WorkerManger用接口衔接起来。然后在子类的任何一个Widget中都可以访问了
在main函数中要连接程序退出的信号,以此来释放WorkManager,这样才能正确的释放Worker。