c++11线程池

大佬写的东西,顶礼膜拜,用到了C++11很多的新知识

后面附有我的思考,不保证对,“?”处是我疑惑的地方

ThreadPool.h

//
// Created by zfr on 2020/9/20.
//

#ifndef PRACTICE_THREADPOOL_H
#define PRACTICE_THREADPOOL_H

#include<vector>
#include<queue>
#include<memory>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<future>
#include<functional>
#include<stdexcept>

class ThreadPool{
public:
    explicit ThreadPool(size_t);//构造函数,explicit禁止初始化时的参数类型的隐式转换
    
    //变长参数模版
    template<class F, class... Args>
            auto enqueue(F&& f, Args&&... args)
            -> std::future<typename std::result_of<F(Args...)>::type>;
    ~ThreadPool();//析构函数

private:
    std::vector<std::thread> workers;   //工作向量空间
    std::queue<std::function<void()> > tasks;   //任务队列

    std::mutex queue_mutex; //互斥量
    std::condition_variable condition;  //条件变量
    bool stop;  //停止标志
};

inline ThreadPool::ThreadPool(size_t threads) :stop (false) {//构造函数,初始化列表初始化stop为false
    for(size_t i = 0; i < threads; ++i){
        workers.emplace_back([this]{//分清楚emplace与push在vector中的区别,emplace效率更高
            for(;;){//相当于while(true)
                std::function<void()> task;//声明了一个返回值void,无参的函数task
                {
                    std::unique_lock<std::mutex> lock(this->queue_mutex);
                    this->condition.wait(lock, [this]{
                        return this->stop || !this->tasks.empty();});//开始stop为false并且tasks为空,阻塞当前线程
                    if(this->stop && this->tasks.empty())//stop为真,并且任务队列为空,直接返回
                        return;
                    task = std::move(this->tasks.front());//将任务队列最前面的任务移给task,函数绑定?回调函数?函数指针?
                    this->tasks.pop();//删除任务队列最前面的任务
                }
                task();//执行
            }
        });
    }
}

//后置返回值 返回了一个异步调用的结果,存储在future中,返回类型为F函数的类型
//变长参数模版
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type> {//后置返回值 返回了一个异步调用的结果,存储在future中,返回类型为F函数的类型
    using return_type = typename std::result_of<F(Args...)>::type;//给返回类型取了个新名字
    //forword作用是获取参数原有类型,和右值引用有关,获取原始数据
    //bind 将后面的变长函数参数和函数f绑定在一起,形成一个新的可调用实体
    //新建一个子线程,把这个新的可调用实体交给子线程去执行
    //返回的是一个shared_ptr智能指针
    auto task = std::make_shared<std::packaged_task<return_type()> >(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
    );
    //将package_task中的future取出来与新的future联系在一起,共享状态值,return_type为返回参数类型
    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);//用unique_lock对mutex进行包装,管理mutex对象
        
        if (stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");

        tasks.emplace([task]() { (*task)(); });//继续将任务加入任务队列;lambda表达式,返回值是一个函数指针???又回调???
    }
    condition.notify_one();//给wait那边发送消息,此时tasks中已有任务,tasks非空
    return res;
}

inline ThreadPool::~ThreadPool(){
    {
        std::unique_lock<std::mutex> lock(queue_mutex);//用unique_lock包装mutex变量
        stop = true;
    }
    condition.notify_all();//给所有的wait发送通知
    for(std::thread &worker: workers)//等待所有的工作子线程结束,注意引用符号,不知道这里能不能用auto?
        worker.join();
}
#endif //PRACTICE_THREADPOOL_H

ThreadPool.cpp

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


int main(){
    ThreadPool pool(4);
    auto result = pool.enqueue([](int answer) { return answer; }, 42);
    std::cout<<result.get()<<std::endl;
}

posted on 2020-09-20 20:49  张芙蓉  阅读(224)  评论(0编辑  收藏  举报

导航