c++ 线程池的实现

  线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。            -----维基百科

:如果对多线程还不够了解可以学习这篇博客,讲的非常好。https://www.cnblogs.com/haippy/p/3284540.html

  线程池主要包括以下几个功能组成:
1、工作线程:一般初始化线程池中的维护的线程个数,当没有任务的时候,线程处于阻塞状态。直到添加新的任务到线程池中,则随机唤醒其中一个线程,来处理任务。当有多个任务到来时,则随机唤醒多个线程来处理任务。
2、任务接口:添加任务的接口,以供工作线程调度任务的执行。
3、任务队列:添加的任务先放到任务队列中去,当任务队列不为空时,则唤醒线程执行任务。

下面是代码实现,通过代码讲解工作池的实现详细过程:

#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <assert.h>
#include <iostream>

//任务,一般的任务都是函数处理,当然这里函数不一定是void()类型,可以定义任务函数类型
typedef std::function<void()> worker_task;

class ThreadPool {
public:
    ThreadPool(size_t);
    template<class F, class... Args>  //任务函数参数可以是变长的
    //->是c11新特性:尾返回类型。其中std::result_of<F(Args...)>::type其中是获取任务函数返回值类型
    auto addTask(F&& f, Args&&... args)-> std::future<typename std::result_of<F(Args...)>::type>;
    ~ThreadPool();
protected:
    // 线程池维护的线程个数
    std::vector< std::thread > workers;
private:
    ThreadPool(const ThreadPool&);//禁止复制拷贝.
    const ThreadPool& operator=(const ThreadPool&);//禁止赋值


    // 任务队列
    std::queue<std::function<void()> > tasks;

    // 锁和条件变量
    std::mutex queue_mutex;
    std::condition_variable condition;//当任务为空时,阻塞线程。当新任务到来时唤醒线程。
    bool stop;
};

// 构造函数初始化线程的个数,用户自定义个数,可以根据自身电脑核的配置来设定。
inline ThreadPool::ThreadPool(size_t threads)
        :   stop(false)
{
    for(size_t i = 0;i<threads;++i)
        workers.emplace_back(
                [this] //匿名函数
                {
                    for(;;)
                    {
                        std::function<void()> task;
                        {
                            std::unique_lock<std::mutex> lock(this->queue_mutex);
                            //如果任务队列为空,则线程会处于阻塞状态。
                            this->condition.wait(lock,
                                                 [this]{ return this->stop || !this->tasks.empty(); });
                            if(this->stop && this->tasks.empty())
                                return;
                            //当任务不为空时,则被唤醒,获取任务队列队首的任务
                            task = std::move(this->tasks.front());
                            this->tasks.pop();
                        }
                        task();//任务函数
                    }
                }
        );
}

// 添加新的任务到线程池中
template<class F, class... Args>
auto ThreadPool::addTask(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
    using return_type = typename std::result_of<F(Args...)>::type;//获取函数返回值类型

	//std::packaged_task包装一个可调用的对象,并且允许异步获取该可调用对象产生的结果。
	//具体可以参考上面给的链接
    auto task = std::make_shared< std::packaged_task<return_type()> >(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
    );
    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);

        if(stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");

        tasks.emplace([task](){ (*task)(); });//将任务放入任务队列
    }
    condition.notify_one();//唤醒阻塞的线程(随机唤醒的线程)
    return res;
}

// 析构函数
inline ThreadPool::~ThreadPool()
{
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        stop = true;
    }
    condition.notify_all();
    for(std::thread &worker: workers)
        worker.join();
}


//子类
class WorkerPool:ThreadPool{

    std::vector<std::future<void>> futures;

public:

    using ThreadPool::ThreadPool;
    //添加任务
    void launch(worker_task&);
    void wait_all(void);

};
void WorkerPool::launch(worker_task &task) {
    for(int i=0;i<workers.size();i++)
    {
        futures.push_back(addTask(task));
    }

}
void WorkerPool::wait_all() {
    for(auto& future:futures){
        future.wait();
    }
    futures.clear();
}

//测试
std::atomic<int>a(0);
void helper()
{
    for(int i=0;i<1000;i++)
        a++;
}
int main(){
    WorkerPool p(2);//构造线程池,并给线程池初始化为2个线程
    std::function<void()>task1(helper);
    std::function<void()>task2(helper);
    p.launch(task1);
    p.launch(task2);
    std::cout<<a<<endl;
}

转载代码地址:
https://github.com/progschj/ThreadPool

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值