qt 利用线程池和锁搭建客户端框架(二)

    这一篇主要设计了业务线程的管理,我设计的业务线程分两种,一种是单次执行,执行完了就释放;每当有新任务时,就新建一个,然后用线程池来启动,如果当前没有空闲线程,它会等到有空闲线程时,再执行这个任务;执行完了之后会自动释放。由于这种单次执行比较灵活,只是在用到的地方新建、然后启动就可以了,当有消息时会用信号通知,出不用管理释放,所以我没有对这种类型进行管理。下面介绍死循环线程的管理。

首先声明接口

#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。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值