c++线程池

一、问题点:

       在实际开发过程中,我们会时常和线程打交道,而且c++11及之后为我们提供了线程等相关的库。当我们需要完成某些任务但是又不想主线程被阻塞,那么创建一个线程是我们的首选。那么问题来了,既然我们能根据需求创建多个线程,那么为啥扯到线程池呢?

二、什么是线程池:

       单从字面意思看,线程池不就是存放线程的容器(池)。这是一种通俗的理解。维基百科上的解释是:在计算机编程中,线程池是用于实现计算机程序中的执行的并发性的软件设计模式。通常也称为复制工作者或工作人员模型,线程池维护多个线程,等待由监督程序分配任务以便并发执行。下面是线程池的原来示意图:

       

 

 

       线程池有两个核心概念,一个是任务队列:负责存放主线程需要处理的任务;一个是工作线程队列:负责从任务队列中取出和运行任务,工作线程队列是一个死循环。线程池相当于一个生产者和消费者的模型。

三、使用线程池的好处:

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

四、如何实现线程池:

        其实Windows早就为我们使用线程池提供了大量的API,如果在Windows系统开发且对Windows API熟悉的同学,使用Windows API就足够了,只需要掌握其使用方式就可以了。但是对于c++开发,c++标准没有为我们提供线程池的库,但是c++11提供了线程库以及一系列同步和互斥组件,使得我们实现一个线程池容易很多。下面的线程池实现代码是直接使用其他大佬写的(在此声明),贴出来方便今后查看。代码如下:

 1 class ThreadPool
 2 {
 3 public:
 4     explicit ThreadPool(size_t threadNum)
 5     {
 6         for (auto i = 0; i < threadNum; ++i)
 7         {
 8             _works.emplace_back([this]()
 9             {
10                 for (;;)
11                 {
12                     std::function<void()> task;
13                     {
14                         std::unique_lock<std::mutex> ul(_mtx);
15                         _cv.wait(ul, [this]() { return _stop || !_tasks.empty(); });
16                         if (_stop && _tasks.empty())
17                         {
18                             return;
19                         }
20                         task = std::move(_tasks.front());
21                         _tasks.pop();
22                     }
23                     task();
24                 }
25             });
26         }
27     }
28 
29     ~ThreadPool()
30     {
31         {
32             std::unique_lock<std::mutex> ul(_mtx);
33             _stop = true;
34         }
35 
36         _cv.notify_all();
37        
38         for (auto& work : _works)
39         {
40             work.join();
41         }
42 
43     }
44 
45     template <typename F, typename... Args>
46     auto submit(F&& f, Args&&... args)->std::future<decltype(f(args...))>
47     {
48         auto taskPtr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(
49             std::bind(std::forward<F>(f), std::forward<Args>(args)...)
50                 );
51 
52         {
53             std::unique_lock<std::mutex> ul(_mtx);
54             if (_stop)
55             {
56                 throw std::runtime_error("submit on stopped ThreadPool.");
57             }
58             _tasks.emplace([taskPtr]() { (*taskPtr)(); });
59         }
60 
61         _cv.notify_all();
62         return taskPtr->get_future(); //线程return的结果
63     }
64 private:
65     bool _stop = false;
66     std::vector<std::thread> _works;            //工作线程队列
67     std::queue<std::function<void()>> _tasks; //任务队列
68     std::mutex _mtx;
69     std::condition_variable _cv;
70 };

参考资料:

1、https://zh.wikipedia.org/wiki/线程池

2、知乎《线程池的c++实现》

转载于:https://www.cnblogs.com/smartNeo/p/11489085.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值