免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12345下一页
最近访问板块 发新帖
查看: 15387 | 回复: 42
打印 上一主题 下一主题

[C++] 谁来来帮我看看这个简单的线程池(c++11) [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-04-30 00:07 |只看该作者 |倒序浏览
20可用积分
本帖最后由 lost_templar 于 2014-04-30 00:09 编辑
  1. #include <cstddef>
  2. #include <functional>
  3. #include <queue>
  4. #include <thread>
  5. #include <vector>
  6. #include <mutex>
  7. #include <atomic>
  8. #include <algorithm>

  9.     namespace simple_thread_pool_private_sdnjasfdlkj
  10.     {
  11.         template< typename Container_Type >
  12.         struct thread_join_guard
  13.         {
  14.             Container_Type & container;
  15.             explicit thread_join_guard( Container_Type& container_ ) : container( container_ ) {}
  16.             ~thread_join_guard()
  17.             {
  18.                 for ( auto& the_thread : container )
  19.                     if ( the_thread.joinable() )
  20.                         the_thread.join();
  21.             }
  22.         };
  23.     }//namespace simple_thread_pool_private_sdnjasfdlkj

  24.     struct simple_thread_pool
  25.     {
  26.         typedef std::function<void()>                                           function_type;

  27.         std::atomic_bool                                                        all_done_flag;
  28.         std::queue<function_type>                                               work_queue;
  29.         std::mutex                                                              work_queue_mutex;
  30.         std::vector<std::thread>                                                thread_array;

  31.         simple_thread_pool_private_sdnjasfdlkj::thread_join_guard<std::vector<std::thread>> joiner;

  32.         simple_thread_pool() : all_done_flag{ false }, joiner{ thread_array }
  33.         {
  34.             std::size_t const max_threads = std::thread::hardware_concurrency();

  35.             for ( std::size_t index = 0; index != max_threads; ++index )
  36.                 thread_array.push_back( std::thread{ &simple_thread_pool::work_loader, this } );
  37.     }

  38.         ~simple_thread_pool()
  39.         {
  40.             all_done_flag = true;
  41.         }

  42.         template< typename Function >
  43.         void commit_work( Function f )
  44.         {
  45.             std::lock_guard<std::mutex> lk{ work_queue_mutex };
  46.             work_queue.emplace( function_type{f} );
  47.         }

  48.         void work_loader()
  49.         {
  50.             while ( ! all_done_flag )
  51.             {
  52.                 function_type current_work;

  53.                 {
  54.                     std::lock_guard<std::mutex> lg{ work_queue_mutex };
  55.                     if ( work_queue.empty() )
  56.                     {
  57.                         current_work = [](){ std::this_thread::yield(); };
  58.                     }
  59.                     else
  60.                     {
  61.                         current_work = work_queue.front();
  62.                         work_queue.pop();
  63.                     }
  64.                 }

  65.                 current_work();
  66.             }
  67.         }

  68.         simple_thread_pool( simple_thread_pool const& ) = delete;
  69.         simple_thread_pool& operator = ( simple_thread_pool const& ) = delete;
  70.         simple_thread_pool( simple_thread_pool && ) = delete;
  71.         simple_thread_pool& operator = ( simple_thread_pool && ) = delete;

  72.     };//struct simple_thead_pool
复制代码
随手写了准备这么用的:

  1.         std::vector<result_type> accumulator_array( ... );
  2.         {
  3.             simple_thread_pool stp;
  4.             for ( ... )
  5.             {               
  6.                 stp.commit_work( [&accumulator_array,..]{...;} );
  7.             }        
  8.         }

  9.        auto const ans = *std::max_element( accumulator_array.begin(), accumulator_array.end() );
复制代码
发现老是在退出前还没有执行完 commit_work 注册的函数~~

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
2 [报告]
发表于 2014-04-30 00:20 |只看该作者

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2014-04-30 00:21 |只看该作者

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
4 [报告]
发表于 2014-04-30 00:45 |只看该作者
sdnjasfdlkj,猛一看还以为是乱码……

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2014-04-30 01:49 |只看该作者

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
6 [报告]
发表于 2014-04-30 09:10 |只看该作者
昨晚没仔细看代码,今天一看顿觉I服了U啊……

std::queue拿来做同步真得大丈夫?线程在那里忙循环不怕烧CPU?看到“!all_done_flag”就结束你也不管queue里还有没有剩下的东西?
……
太多了,不吐槽了,lz还是先补补课吧

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
7 [报告]
发表于 2014-04-30 14:11 |只看该作者
回复 6# windoze

很少写基于 cpu 的并行程序,求指点。


   

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
8 [报告]
发表于 2014-04-30 15:19 |只看该作者
回复 6# windoze


    你耐心点看完他的代码, 跟本不会有你说的这两个问题,这两个问题都考虑到了,只不过CPU忙等待解决的方法不太好罢了。

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
9 [报告]
发表于 2014-04-30 15:28 |只看该作者
本帖最后由 gaojl0728 于 2014-04-30 15:33 编辑

回复 1# lost_templar


整体而言程序还可以,有两个问题需要指出。
1. CPU空循环的问题, std::this_thread::yield()虽然可以释放当前的CPU时间, 等并不能阻止内核还会调度这个线程,下次跑进来一样会浪费CPU的时间,更好的解决办法使用条件变量解决。
队列位空的时空等待条件变量, 然后在commit_work里面**条件变量
2. 你的线程永远不会退出, simple_thread_pool析构时会等待所有线程退出, 然后会设置all_done_flag = true, 但是线程只有在all_done_flag为true才会退出,看到了没,这里就锁死了

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
10 [报告]
发表于 2014-04-30 15:45 |只看该作者
gaojl0728 发表于 2014-04-30 15:28
回复 1# lost_templar


回复 1# lost_templar


整体而言程序还可以,有两个问题需要指出。
1. CPU空循环的问题, std::this_thread::yield()虽然可以释放当前的CPU时间, 等并不能阻止内核还会调度这个线程,下次跑进来一样会浪费CPU的时间,更好的解决办法使用条件变量解决。
队列位空的时空等待条件变量, 然后在commit_work里面**条件变量
2. 你的线程永远不会退出, simple_thread_pool析构时会等待所有线程退出, 然后会设置all_done_flag = true, 但是线程只有在all_done_flag为true才会退出,看到了没,这里就锁死了


待我想想

对于2,我认为是先把 all_done_flag 设置为 true,然后才析构 thread_join_guard 等待所有线程退出的,难道是我理解错了?我写段代码测试一下。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP