一个简单的C++线程池demo

demo代码包含两个类,一个是ThreadPool类,对线程池做了封装,另一个FunGroup类,用于线程池的串行处理。

线程池类可以用并行或串行的方式执行可调用对象。当并行执行可调用对象时,只需要调用AddFun函数将调用对象直接传入fun_queue_队列中,另外唤醒睡眠中的子线程处理该可调用对象。当串行执行可调用对象时,需要在AddFun函数指定可调用对象所属的队列组,该队列组保存在fun_groups_中,队列组中的可调用对象依赖于上一个可调用对象执行完成才能被执行。

ThreadPool.h

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <vector>
#include <queue>
#include <map>
#include <memory>
#include <thread>
#include <mutex>
#include <string>
#include <functional>
#include <condition_variable>

#include "FunGroup.h"

class ThreadPool
{
public:
    typedef std::function<void()> functor;

    ThreadPool(int n);
    ~ThreadPool();
    //启动线程池
    void Start();
    bool IsStop();
    //将可调用对象传入线程池等待执行
    void AddFun(functor fun,std::string group_str="");

private:
    //子线程入口
    void ThreadFun(int threadId);

    int threadNum_;//线程个数
    int sleepThreadNum_;//睡眠线程个数
    std::vector<std::thread> threads_;//子线程数组
    std::mutex mutex_;
    std::condition_variable cond_;
    std::queue<functor> fun_queue_;//可调用对象队列
    std::map<int,std::shared_ptr<FunGroup>> fun_groups_;//可调用对象组
    bool stop_;
};

#endif

ThreadPool.cpp

#include "ThreadPool.h"
#include <iostream>

ThreadPool::ThreadPool(int n)
    :threadNum_(std::max(n,1)),
     sleepThreadNum_(0),
     stop_(false)
{

}

ThreadPool::~ThreadPool()
{
    {
        //唤醒子线程并退出
        std::unique_lock<std::mutex> lock(mutex_);
        stop_ = true;
        cond_.notify_all();
    }
    for(auto& thread : threads_)
    {
        thread.join();
    }
    std::cout<<"all thread exit"<<std::endl;
}

void ThreadPool::Start()
{
    for(int i=0; i<threadNum_; i++)
    {
        threads_.emplace_back([this,i](){ThreadFun(i);});
    }
}

bool ThreadPool::IsStop()
{
    std::unique_lock<std::mutex> lock(mutex_);
    return stop_;
}

/*
fun:待处理的调用对象
group_str:该调用对象从属的队列组名,若组名为空,表示可并行执行,
若不为空,只能在队列组内串行执行
*/
void ThreadPool::AddFun(functor fun,std::string group_str)
{
    int sleepNum = 0;
    if(group_str.empty())
    {
        std::unique_lock<std::mutex> lock(mutex_);
        fun_queue_.push(fun);
        sleepNum = sleepThreadNum_;
    }
    else
    {
        std::hash<std::string> hash_fn;
        int group_id = hash_fn(group_str);
        if(fun_groups_.count(group_id) == 0)
        {
            //创建队列组
            fun_groups_.insert(std::make_pair(group_id,std::make_shared<FunGroup>(this)));
        }
        fun_groups_[group_id]->AddFun(fun);
        sleepNum = sleepThreadNum_;
    }
    if(sleepNum > 0)
    {
        //唤醒睡眠中的线程,赶紧工作
        cond_.notify_one();
    }
}

void ThreadPool::ThreadFun(int threadId)
{
    while (!IsStop())
    {
        int step = 0;
        functor fun;
        int funNum = 0;
        {
            std::unique_lock<std::mutex> lock(mutex_);
            funNum = fun_queue_.size();
        }

        if(funNum)
        {
            //可调用对象队列不为空,赶紧从队列头取出一个元素处理掉
            int sleepNum = 0;
            {
                std::unique_lock<std::mutex> lock(mutex_);
                fun = fun_queue_.front();
                fun_queue_.pop();
                sleepNum = sleepThreadNum_;
            }

            --funNum;
            if(funNum>0 && sleepThreadNum_>funNum)
            {
                /*取出第一个元素后,队列仍然不为空,但是睡眠的线程数大于当前队列的元素数,
                再多唤醒一个线程一起干活*/
                cond_.notify_one();
            }
            else if(funNum>0 && sleepThreadNum_<=funNum)
            {
                /*取出第一个元素后,队列仍然不为空,而且睡眠的线程数小于当前队列的元素数,
                赶紧唤醒所有线程一起干活*/
                cond_.notify_all();
            }
            step = 1;
        }

        if(step == 0)
        {
            //没有可处理对象,进入睡眠状态
            std::cout<<"thread: "<<threadId<<" sleeping"<<std::endl;
            std::unique_lock<std::mutex> lock(mutex_);
            ++sleepThreadNum_;
            cond_.wait(lock,[this](){return (!fun_queue_.empty() || stop_);});
            //当可调用对象队列不为空,线程被唤醒开始干活,或线程被通知退出
            --sleepThreadNum_;
        }
        else
        {
            std::cout<<"thread: "<<threadId<<" working"<<std::endl;
            fun();
        }
    }
}

FunGroup.h

#ifndef FUNGROUP_H
#define FUNGROUP_H

#include <queue>
#include <functional>
#include <mutex>

class ThreadPool;

class FunGroup
{
public:
    typedef std::function<void()> functor;
    FunGroup(ThreadPool* poolPtr);
    ~FunGroup();
    int Size();
    void AddFun(const functor& fun);
    void Run(const functor& fun);
private:
    ThreadPool* poolPtr_;
    std::queue<functor> fun_queue_;
    std::mutex mutex_;
};

#endif

FunGroup.cpp

#include <functional>
#include "FunGroup.h"
#include "ThreadPool.h"

FunGroup::FunGroup(ThreadPool* poolPtr)
    :poolPtr_(poolPtr)
{

}

FunGroup::~FunGroup()
{

}

int FunGroup::Size()
{
    std::unique_lock<std::mutex> lock(mutex_);
    return fun_queue_.size();
}

void FunGroup::AddFun(const functor& fun)
{
    if(Size() == 0)
    {
        poolPtr_->AddFun(std::bind(&FunGroup::Run,this,fun));
    }
    else
    {
        //当队列不为空,只需将可调用对象放在队列后面
        std::unique_lock<std::mutex> lock(mutex_);
        fun_queue_.push(fun);
    }
}

void FunGroup::Run(const functor& fun)
{
    //执行当前调用对象
    fun();
    if(Size() > 0)
    {
        //若队列不为空,继续执行下一个可调用对象
        functor nextFun;
        {
            std::unique_lock<std::mutex> lock(mutex_);
            nextFun = fun_queue_.front();
            fun_queue_.pop();
        }
        poolPtr_->AddFun(std::bind(&FunGroup::Run,this,nextFun));
    }
}

完整的代码已全部贴出,下面是测试代码

#include "ThreadPool.h"
#include <iostream>
#include <unistd.h>

void test(int i)
{
    std::cout<<i<<std::endl;
    usleep(50);
}

int main()
{
    ThreadPool pool(4);
    pool.Start();
    for(int i=0; i<100; i++)
    {
        auto fun = std::bind(test,i);
        pool.AddFun(fun,"group");
    }

    sleep(3);
    std::cout<<"exit"<<std::endl;

    return 0;
}

运行结果如下,打包工程地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值