qt客户端技术杂谈-线程池(05)

一、qt线程池

线程池的概念只要是程序员大概都知道一些,这里就不重复进行。但大部分线程池都是针对后台业务。那么客户端使用线程池会有什么不同呢,特别是qt客户端,使用线程池获取返回值,会不会影响界面阻塞等。

二、实现原理

实现机制:线程池使用生产者消费者模型,维护一个任务队列,提供一个外部接口给上层应用插入任务到队列中,消费者线程从队列中取走任务,并执行。为了不影响qt本身的消息循环,提供一个同步接口,实现里使用eventLoop,任务执行完后发送信号给eventLoop,使它退出。
###三具体实现
直接上干货

  1. 任务类:
//RztThreadTask.h
#ifndef RZTTHREADTASK_H
#define RZTTHREADTASK_H
#include <QObject>
#include <functional>
using RztThreadFunc = std::function<void()>;
class RztThreadTask : public QObject
{
    Q_OBJECT
public:
    explicit RztThreadTask(RztThreadFunc func);
    RztThreadTask(const RztThreadTask &threadTask);
    void operator=(const RztThreadTask &threadTask);
    RztThreadTask();

    void            process();
    void            operator()();
signals:
    void            sglTaskFinish();//任务完成信号
public slots:
private:
    RztThreadFunc   m_func;
};

//RztThreadTask.cpp
#include "RztThreadTask.h"
#include <QDebug>
RztThreadTask::RztThreadTask(RztThreadFunc func)
{
    m_func = func;
}
RztThreadTask::RztThreadTask(const RztThreadTask &threadTask)
{
    m_func = threadTask.m_func;
}
void RztThreadTask::operator=(const RztThreadTask &threadTask)
{
    m_func = threadTask.m_func;
}
RztThreadTask::RztThreadTask()
{
}
void RztThreadTask::process()
{
    try
    {
        m_func();//真正上层传来的lambda函数
        emit sglTaskFinish();//执行完发完成信号
    }
    catch(std::exception &e)
    {
        qDebug() << "exception error :" << e.what();
    }
    catch(...)
    {
        qDebug() << "exception error : unkonw exception";
    }
}
void RztThreadTask::operator()()
{
    process();//
}
  1. 线程类
    线程类,做的事不多,只是简单的封装下,不喜欢qthread的,可以使用std::thread替换
// RztThread.h
#ifndef RZTTHREAD_H
#define RZTTHREAD_H

#include <QObject>
#include <QThread>
#include "RztThreadTask.h"

class RztThread : public QThread
{
    Q_OBJECT
public:
    explicit RztThread(RztThreadFunc func);
    explicit RztThread(const RztThreadFunc &&func);
    RztThread(const RztThread&) = delete;
    RztThread& operator=(const RztThread&) = delete;
protected:
    void        run();
public slots:
private:
    RztThreadFunc           m_func;
};
#endif // RZTTHREAD_H

//RztThread.cpp
#include "RztThread.h"
RztThread::RztThread(RztThreadFunc func)
    :m_func(func)
{}
RztThread::RztThread(const RztThreadFunc &&func)
    :m_func(func)
{
}
void RztThread::run()
{
    m_func();
}
  1. 线程池类:
    维护任务队列,并进行线程资源管理
//RztThreadPool.h
#ifdef WIN32
  #pragma execution_character_set("utf-8")
#endif
#pragma once
#include <string>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <future>
#include <QObject>
#include <queue>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <functional>
#include "RztThreadTask.h"
#include "RztThread.h"
class  RztThreadPool : public QObject
{
    Q_OBJECT
public:
    RztThreadPool(unsigned short size = 6);
    ~RztThreadPool();

    int idlThreadCount();
    int threadCount();
    bool commit(std::shared_ptr<RztThreadTask> funcPtr);
    void addThread(unsigned short size);
public:
signals:
private:
    std::vector<std::shared_ptr<RztThread>> m_threadPool;     //线程池
    std::queue<std::shared_ptr<RztThreadTask>> m_queueTasks;            //任务队列
    std::mutex m_lock;                   //同步
    std::condition_variable m_taskCon;   //条件阻塞
    std::atomic<bool> m_running{true};     //线程池是否执行
    std::atomic<int>  m_idlThreadNum{0};  //空闲线程数量
};

//RztThreadPool.cpp
#include "RztThreadPool.h"
#include <stdexcept>
#include <QDebug>
#define  THREADPOOL_MAX_NUM 16
RztThreadPool::RztThreadPool(unsigned short size)
{
    addThread(size);
}
RztThreadPool::~RztThreadPool()
{
    m_running=false;
    m_taskCon.notify_all();
    for (auto threadPtr : m_threadPool)
    {
        if(!threadPtr->wait(100))
        {
            qDebug() << "thread not exit:" << threadPtr->currentThreadId();
        }
    }
}
int RztThreadPool::idlThreadCount()
{
    return m_idlThreadNum;
}
int RztThreadPool::threadCount()
{
    return m_threadPool.size();
}
bool RztThreadPool::commit(std::shared_ptr<RztThreadTask> funcPtr)
{
    if (!m_running)
    {
        qDebug() << "threadPool is stopped!";
        return false;
    }
    {
        std::lock_guard<std::mutex> lock(m_lock);
        m_queueTasks.push(funcPtr);
    }

    m_taskCon.notify_one();
    return true;
}
void RztThreadPool::addThread(unsigned short size)
{
    for (; m_threadPool.size() < THREADPOOL_MAX_NUM && size > 0; --size)
    {
        RztThreadFunc funPtr = [=]()
        {
            while (m_running)
            {
                std::shared_ptr<RztThreadTask> funcPtr;
                {
                    std::unique_lock<std::mutex> lock(m_lock);
                    m_taskCon.wait(lock, [this]
                    {
                            return !m_running || !m_queueTasks.empty();
                    });
                    if (!m_running)
                    {
                        return;
                    }
                    funcPtr = m_queueTasks.front();
                    m_queueTasks.pop();
                }
                if(funcPtr)
                {
                    m_idlThreadNum--;
                    (*funcPtr)();
                    m_idlThreadNum++;
                }
            }
        };
        std::shared_ptr<RztThread> threadPtr = std::make_shared<RztThread>(funPtr);
        m_threadPool.push_back(threadPtr);
        threadPtr->start();
        m_idlThreadNum++;
    }
}
  1. 接口类
    提供线程任务接口,主要有异步和同步两种接口,任务参数传一个lambda函数就行
//RztThreadMgr.h
#ifdef WIN32
  #pragma execution_character_set("utf-8")
#endif
#ifndef RZTTHREADMGR_H
#define RZTTHREADMGR_H

#include <QObject>

#include <QEventLoop>
#include <QTimer>
#include <QMutex>
#include <QHash>
#include <thread>
#include "RztThreadPool.h"
class RztThreadMgr : public QObject
{
    Q_OBJECT
public:
    explicit            RztThreadMgr(QObject *parent = nullptr);
    ~RztThreadMgr();
    QObject*            getObject();
    //同步接口
    bool                syncStartOneTask(RztThreadFunc func, int nTime = 1000);
    //异步接口
    void                asyncStartOneTask(RztThreadFunc func);
    void                addThreads(int nNum);
    //空闲线程数量
    int                 idlThreadCount();
    //线程数量
    int                 threadCount();
signals:
public slots:
private:
private:
    std::shared_ptr<RztThreadPool>              m_threadPoolPtr;
    QMutex                                      m_mutex;
};
#endif // RZTTHREADMGR_H

//RztThreadMgr.cpp
#ifdef WIN32
  #pragma execution_character_set("utf-8")
#endif
#include "RztThreadMgr.h"
#include <QMutexLocker>
#include <functional>
#include <QDebug>
#define MAX_TASK_ID 1000000
RztThreadMgr::RztThreadMgr(QObject *parent) :
    QObject(parent), m_mutex(QMutex::Recursive)
{
    m_threadPoolPtr = std::make_shared<RztThreadPool>();
}
RztThreadMgr::~RztThreadMgr()
{
}
QObject *RztThreadMgr::getObject()
{
    return this;
}
bool RztThreadMgr::syncStartOneTask(RztThreadFunc func, int nTime)
{
    QTimer timer;
    std::shared_ptr<QEventLoop> loopPtr = std::make_shared<QEventLoop>();
    std::shared_ptr<RztThreadTask> taskPtr = std::make_shared<RztThreadTask>(func);

    timer.setInterval(nTime);
    connect(&timer, &QTimer::timeout, this, [=](){
        qDebug() << "timeout exit!";
        loopPtr->exit(-1);
    });
    connect(taskPtr.get(), &RztThreadTask::sglTaskFinish, this, [=](){
        loopPtr->exit(0);
        qDebug() << "normal exit!";
    });
    {
        QMutexLocker lock(&m_mutex);
        m_threadPoolPtr->commit(taskPtr);
    }
    timer.start();
    int ret = loopPtr->exec();
    if(ret == -1)
    {
        return false;
    }
    return true;
}
void RztThreadMgr::asyncStartOneTask(RztThreadFunc func)
{
    QMutexLocker lock(&m_mutex);
    std::shared_ptr<RztThreadTask> taskPtr = std::make_shared<RztThreadTask>(func);
    m_threadPoolPtr->commit(taskPtr);
}
void RztThreadMgr::addThreads(int nNum)
{
    QMutexLocker lock(&m_mutex);
    m_threadPoolPtr->addThread(nNum);
}
int RztThreadMgr::idlThreadCount()
{
    QMutexLocker lock(&m_mutex);
    return m_threadPoolPtr->idlThreadCount();
}
int RztThreadMgr::threadCount()
{
    QMutexLocker lock(&m_mutex);
    return m_threadPoolPtr->threadCount();
}
  1. demo测试
    仅截取部分测试函数,示例使用方式,具体可以自己根据应用场景使用
void    Widget::test01()
{
    int count = 0;
    while(true)
    {
        count++;
        threadMgr.asyncStartOneTask(std::bind(&Widget::testLog, this));

        bool ret = threadMgr.syncStartOneTask([](){
            qDebug() << "task test02";
        });

        if(!ret)
        {
            qDebug() << "---------------";
        }
        qDebug() << "task end";

        ret = threadMgr.syncStartOneTask([](){
            qDebug() << "task test03";
        });
        if(!ret)
        {
            qDebug() << "---------------";
        }

        ret = threadMgr.syncStartOneTask([](){
            QThread::msleep(100);
            qDebug() << "task test04";
        });
        if(!ret)
        {
            qDebug() << "---------------";
        }

        QThread::msleep(10);
        if(count > 1000)
        {
            count = 0;
            QThread::msleep(110);
        }
    }

}

void Widget::on_pushButton_clicked()
{
//压力测试
    threadMgr.addThreads(6);
    std::thread thread(std::bind(&Widget::test01, this));
    std::thread thread2(std::bind(&Widget::test01, this));
    std::thread thread3(std::bind(&Widget::test01, this));
    std::thread thread4(std::bind(&Widget::test01, this));
    std::thread thread5(std::bind(&Widget::test01, this));

//普通测试
    test01();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值