c++线程池 progschj/ThreadPool解析

源代码

https://github.com/progschj/ThreadPool.git

这是适应于c++11版本以上的线程池实现,可以添加各种类型线程任务,同时由于使用std::future等新功能,从而能够获得任务的返回值。在github上有3.2k的star。

最后有疑问,求大佬解惑(已经理解了,切换任务并非时刻进行,若上一个任务正在进行,则代码运行在task(),此时不会切换任务)

线程池雏形

c++线程池有一个比较基本的模型,我看了一些工程,发现它们的基本构造都可以从这篇博客中理解。

https://www.cnblogs.com/ailumiyana/p/10016965.html

简要叙述线程池原理

线程池通常实现为一个类ThreadPool。该类主要包含4个功能:

1. 线程池管理器(构造函数,让当前空闲进程取队列的头任务运行; 析构函数,等待线程结束)

2. 工作线程(vector<thread>)

3. 任务接口(addTask或enqueue)

4. 任务队列( 一般使用queue)

关键点:

1. 建立线程池时,指定一定数量的线程,开启,每个线程的任务就是当队列不为空时且当前没有运行任务时,取任务并运行(通过条件互斥量实现)

2. 每当有任务来时,存入任务队列,并通知每个线程(通过条件互斥量实现)

 

涉及到的c++11特性

1. 匿名函数  比较简单

2. 可变模板参数

3. std::bind  

4. std::future、std::packaged_task

5. std::function

- 其中235是重点,std::function可以用于函数指针, std::function+std::bind可以实现将一个和function声明时不同的函数绑在一起

- std::bind+可变参数模板可以实现任意函数都能绑定到function上。

举例:

template<class F, class... Args>
int push(F&& f, Args&&... args)
{
    std::function<void()> task;
    task = std::bind(f, args...);
    task();
    return 1;
}

std::future则是用于获得线程函数的返回值,通过get()方法可以实现。

代码

代码总共分两部分:ThreadPool.h和example.cpp。虽然还有一些c++特性,但大体上可以忽略那些无关紧要的特性了(forward)

ThreadPool.h中部分解释:

// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads)
    :   stop(false)
{
    for(size_t i = 0;i<threads;++i)
        workers.emplace_back(
            //这下面按道理是一个thread的构造函数,因为emplace_back(thread)。
            //thread t1(这个匿名函数)
            //这个匿名函数作用就是取出队列的东西运行
            [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就是之前存放的匿名函数,执行这个匿名函数就是在执行任务
                    task();
                }
            }
        );
}

// add new work item to the pool
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) 
    -> std::future<typename std::result_of<F(Args...)>::type>
{
    using return_type = typename std::result_of<F(Args...)>::type;

    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);

        // don't allow enqueueing after stopping the pool
        if(stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");

        //现在相当于向队列中放了一个匿名函数,这个匿名函数没有参数,调用的时候会执行。
        tasks.emplace([task](){ (*task)(); });
    }
    condition.notify_one();
    return res;
}


#endif

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值