Qt实现简单线程池

Qt本身就具备线程池类QThreadPool,使用起来也很方便,不过现在我们用QThread来做一个自己的线程池。

创建用来管理线程池的类ThreadPool,在这里它发挥着管家的职责,掌管公共资源的使用。由于管理任务的队列、锁以及条件变量都声明了私有,所以给WorkThread声明为友元类,以便其能访问。

为了简单,我们只定义了一个构造函数以及三个函数:

  • ThreadPool(int count,QObject*parent=nullptr) 其中count表示要在线程池中创建多少个子线程
  • void PushTask(Task) 用于添加待执行的任务,Task是个函数对象,我们在调用的时候就不用显示的指定参数了,其功能就是实现简单的加法
  • void Start() 控制开始运行
  • void Destroy() 销毁所有子线程

关于子线程的管理我们使用的智能指针,以方便资源自动释放。下面就是ThreadPool的实现:

//头文件

//线程池
class ThreadPool : public QObject
{
    Q_OBJECT
public:
    explicit ThreadPool(int count,QObject *parent = nullptr);
    ~ThreadPool();

    void PushTask(Task);
    void Start();
    void Destroy();

private:
    QList<Task> m_Tasks; // 任务队列
    QList<QSharedPointer<WorkThread>> m_Threads; //运行的线程
    bool m_bStop; //停止线程

    QMutex m_TaskMutex;
    QWaitCondition m_NotEmpty;

    friend class WorkThread;
};

//实现
ThreadPool::ThreadPool(int count,QObject *parent) : QObject(parent),m_bStop(false)
{
    for(int i=0;i<count;i++)
        m_Threads.push_back( QSharedPointer<WorkThread>(new WorkThread(this)));
}

ThreadPool::~ThreadPool()
{
    Destroy();
}

void ThreadPool::PushTask(Task task)
{
    m_TaskMutex.lock();
    m_Tasks.push_back(task);
    m_NotEmpty.wakeOne();
    m_TaskMutex.unlock();
}

void ThreadPool::Start()
{
    foreach (auto thread, m_Threads)
    {
        thread->start();
    }
}

void ThreadPool::Destroy()
{
    m_bStop = true;
    m_NotEmpty.wakeAll();

    //等待线程退出
    foreach (auto thread, m_Threads)
    {
        if(!thread->isFinished())
            thread->wait();
    }

    //清空 智能指针自动释放
    m_Threads.clear();
}

以WorkThread做为线程池中的子线程,所以要继承QThread,并重新实现run()函数。

由于公共资源都在ThreadPool中,所以我们定义了一个父类指针m_Pool来使用公共资源。

还定义了 m_Handle,主要为了下析构时打印线程ID,关于这块大家可以参考我以前测试的一个例子https://blog.csdn.net/hanzhaoqiao1436/article/details/80957945

实现如下:

//头文件

//执行线程
class WorkThread:public QThread
{
public:
    WorkThread(ThreadPool* parent);
    ~WorkThread();

protected:
    virtual void run();

private:
    ThreadPool* m_Pool;
    Qt::HANDLE m_Handle;
};

//实现
WorkThread::WorkThread(ThreadPool *parent)
{
    m_Pool = parent;
}

WorkThread::~WorkThread()
{
    qDebug() << __FUNCTION__ << m_Handle << "Thread quit: " << isFinished();
}

void WorkThread::run()
{
    m_Handle = QThread::currentThreadId();
    while(!m_Pool->m_bStop)
    {
        m_Pool->m_TaskMutex.lock();
        while(m_Pool->m_Tasks.isEmpty())
        {
            qDebug() << QThread::currentThreadId() << QString::fromLocal8Bit("进入等待");
            m_Pool->m_NotEmpty.wait(&m_Pool->m_TaskMutex);
            qDebug() << QThread::currentThreadId() << QString::fromLocal8Bit("被唤醒");

            //线程退出条件判断
            if(m_Pool->m_bStop)
            {
                m_Pool->m_TaskMutex.unlock();
                return;
            }
        }

        //取出任务
        Task task = m_Pool->m_Tasks.front();
        m_Pool->m_Tasks.pop_front();
        m_Pool->m_TaskMutex.unlock();

        if(task)
        {
            //执行任务
            task();
        }
    }
}

差点忘了贴函数对象Task的定义-_-|| I'm sorry

//任务类型
class Task
{
public:
    Task(int a,int b):m_a(a),m_b(b){}
    void operator ()()const
    {
        QThread::msleep(300);
        qDebug() << QThread::currentThreadId() << QString::fromLocal8Bit("执行任务") << m_a << "+" << m_b << "=" << m_a+m_b;
    }
    operator bool() const
    {
        //如果做除法这里可以判断下
        if(m_b == 0)
            return false;

        return true;
    }
private:
    int m_a,m_b;
};

调用测试:

    //创建三个子线程
    m_Pool(new ThreadPool(3,this));

    //直接启动线程
    m_Pool->Start();

    //此时能看到所有线程都进入等待状态
    QThread::msleep(100);

    //添加任务
    for(int i=0;i<4;i++)
    {
        m_Pool->PushTask(Task(qrand(),qrand()));
    }

运行结果:

0x17fc "进入等待"
0x1990 "进入等待"
0x1298 "进入等待"
0x1298 "被唤醒"
0x1990 "被唤醒"
0x17fc "被唤醒"
0x1990 "执行任务" 26500 + 6334 = 32834
0x1298 "执行任务" 18467 + 41 = 18508
0x17fc "执行任务" 15724 + 19169 = 34893
0x1298 "进入等待"
0x17fc "进入等待"
0x1990 "执行任务" 29358 + 11478 = 40836
0x1990 "进入等待"

(调用Destroy)
0x1298 "被唤醒"
0x17fc "被唤醒"
0x1990 "被唤醒"
~WorkThread 0x1298 Thread quit:  true
~WorkThread 0x1990 Thread quit:  true
~WorkThread 0x17fc Thread quit:  true

假如我们在Destroy()中,不停止直接释放子线程,线程会自动停下来吗?答案当然是否定的。比如说我们注释掉停止的相关调用

void ThreadPool::Destroy()
{
    //m_bStop = true;
    //m_NotEmpty.wakeAll();

    //等待线程退出
    //foreach (auto thread, m_Threads)
    //{
    //    if(!thread->isFinished())
    //        thread->wait();
    //}

    //清空 智能指针自动释放
    m_Threads.clear();
}


(会看到如下结果)
~WorkThread 0x1958 Thread quit:  false
QThread: Destroyed while thread is still running

(附上程序源码,欢迎大家指点错误)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值