最近在看面经的过程中遇到一个问题 线程池的实现 我想了想 完全不会啊 于是就开始了我的线程池学习之路
在网上仔细研究了一下那个100行的C++线程池代码(那个作者在花式秀C++11),不过有一说一 他写的确实好。
先上代码
1 #include <vector> 2 #include <queue> 3 #include <memory> 4 #include <thread> 5 #include <mutex> 6 #include <condition_variable> 7 #include <future> 8 #include <functional> 9 #include <stdexcept> 10 #include <iostream> 11 12 using namespace std; 13 14 class ThreadPool { 15 public: 16 ThreadPool(size_t); //构造函数,size_t n 表示连接数 17 18 template<class F, class... Args> 19 auto enqueue(F &&f, Args &&... args) //任务管道函数 20 -> std::future<typename std::result_of<F(Args...)>::type>; // 利用尾置限定符 std future用来获取异步任务的结果 21 22 ~ThreadPool(); 23 24 private: 25 // need to keep track of threads so we can join them 26 std::vector<std::thread> workers; //追踪线程 27 // the task queue 28 std::queue<std::function<void()> > tasks; //任务队列,用于存放没有处理的任务。提供缓冲机制 29 30 // synchronization 同步? 31 std::mutex queue_mutex; //互斥锁 32 std::condition_variable condition; //条件变量? 33 bool stop; 34 }; 35 36 // the constructor just launches some amount of workers 37 inline ThreadPool::ThreadPool(size_t threads) : stop(false) { 38 for (size_t i = 0; i < threads; ++i) 39 workers.emplace_back( //以下为构造一个任务,即构造一个线程 40 [this] { 41 for (;;) { 42 std::function<void()> task; //线程中的函数对象 43 {//大括号作用:临时变量的生存期,即控制lock的时间 44 std::unique_lock<std::mutex> lock(this->queue_mutex); 45 this->condition.wait(lock, 46 [this] { 47 return this->stop || !this->tasks.empty(); 48 }); //当stop==false&&tasks.empty(),该线程被阻塞 !this->stop&&this->tasks.empty() 49 if (this->stop && this->tasks.empty()) return; 50 task = std::move(this->tasks.front()); 51 this->tasks.pop(); 52 } 53 task(); //调用函数,运行函数 54 } 55 } 56 ); 57 } 58 59 // add new work item to the pool 60 template<class F, class... Args> 61 auto ThreadPool::enqueue(F &&f, Args &&... args) //&& 引用限定符,参数的右值引用, 此处表示参数传入一个函数 62 -> std::future<typename std::result_of<F(Args...)>::type> { 63 using return_type = typename std::result_of<F(Args...)>::type; 64 //packaged_task是对任务的一个抽象,我们可以给其传递一个函数来完成其构造。之后将任务投递给任何线程去完成,通过 65 //packaged_task.get_future()方法获取的future来获取任务完成后的产出值 66 auto task = std::make_shared<std::packaged_task<return_type()> >( //指向F函数的智能指针 67 std::bind(std::forward<F>(f), std::forward<Args>(args)...) //传递函数进行构造 68 ); 69 //future为期望,get_future获取任务完成后的产出值 70 std::future<return_type> res = task->get_future(); //获取future对象,如果task的状态不为ready,会阻塞当前调用者 71 { 72 std::unique_lock<std::mutex> lock(queue_mutex); //保持互斥性,避免多个线程同时运行一个任务 73 // don't allow enqueueing after stopping the pool 74 if (stop) throw std::runtime_error("enqueue on stopped ThreadPool"); 75 tasks.emplace([task]() { (*task)(); }); //将task投递给线程去完成,vector尾部压入 76 } 77 condition.notify_one(); //选择一个wait状态的线程进行唤醒,并使他获得对象上的锁来完成任务(即其他线程无法访问对象) 78 return res; 79 }//notify_one不能保证获得锁的线程真正需要锁,并且因此可能产生死锁 80 81 // the destructor joins all threads 82 inline ThreadPool::~ThreadPool() { 83 { 84 std::unique_lock<std::mutex> lock(queue_mutex); 85 stop = true; 86 } 87 condition.notify_all(); //通知所有wait状态的线程竞争对象的控制权,唤醒所有线程执行 88 for (std::thread &worker: workers) 89 worker.join(); //因为线程都开始竞争了,所以一定会执行完,join可等待线程执行完 销毁进程池里面的进程 90 } 91 92 char the_task(int i) { 93 std::cout << "worker thread ID:" << std::this_thread::get_id() << std::endl; 94 return 'a' + i; 95 } 96 97 98 int main() { 99 ThreadPool pool(4); 100 std::vector<std::future<char> > results; 101 for (int i = 0; i < 8; ++i) results.emplace_back(pool.enqueue(the_task, i)); 102 for (auto &&result: results) //通过future.get()获取返回值 103 std::cout << result.get() << ' '; 104 std::cout << std::endl; 105 106 return 0; 107 }