免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: lost_templar

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

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2014-04-30 16:39 |显示全部楼层
回复 19# lost_templar


    将近6万行,还是算了

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
发表于 2014-04-30 16:55 |显示全部楼层
真费劲啊,还是我来吧, 我也整个gcc4.9试下。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2014-04-30 16:58 |显示全部楼层
回复 21# gaojl0728


    问题应该是如猫蜀黍所说的,没有等待 queue 中的工作全部做完就退出了,但是不知道怎么改正。
    编译器无所谓了,从 4.8 往上应该都可以

论坛徽章:
17
处女座
日期:2013-08-27 09:59:352015亚冠之柏太阳神
日期:2015-07-30 10:16:402015亚冠之萨济拖拉机
日期:2015-07-29 18:58:182015年亚洲杯之巴勒斯坦
日期:2015-03-06 17:38:17摩羯座
日期:2014-12-11 21:31:34戌狗
日期:2014-07-20 20:57:32子鼠
日期:2014-05-15 16:25:21亥猪
日期:2014-02-11 17:32:05丑牛
日期:2014-01-20 15:45:51丑牛
日期:2013-10-22 11:12:56双子座
日期:2013-10-18 16:28:17白羊座
日期:2013-10-18 10:50:45
发表于 2014-04-30 17:37 |显示全部楼层
回复 1# lost_templar


    在 while ( ! all_done_flag )循环外把还在队列中的任务执行一下。

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
发表于 2014-04-30 17:47 |显示全部楼层
本帖最后由 gaojl0728 于 2014-04-30 17:49 编辑

回复 22# lost_templar


gcc4.9编译还挺麻烦的,依赖很多。

又看了一下你的代码, 但看逻辑的确会有这个问题, 虽然容易修正, 但是会有潜在的风险,simple_thread_pool开始析构以后,joiner会等待线程执行完成,这时候work_queue_mutex,work_queue对象必须得还在内存没有被析构才行。
所以你得保证joiner必须在work_queue_mutex,work_queue之前析构才能保证代码完全没问题, 你可以试一下是不是按照这个顺序析构的。
而且你得保证这几个变量定义的顺序在将来不会被修改。一旦修改风险就来了。
这也是个典型的反面教材啊。

while ( ! all_done_flag && !work_queue.empty())
{
    function_type current_work;

    {
        std::lock_guard<std::mutex> lg{ work_queue_mutex };
        if ( work_queue.empty() )
        {
            current_work = [](){ std::this_thread::yield(); };
        }
        else
        {
            current_work = work_queue.front();
            work_queue.pop();
        }
    }

    current_work();
}

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2014-04-30 17:55 |显示全部楼层
第一句
while ( ! all_done_flag && !work_queue.empty())
这里后边加上个 !work_queue.empty() 不是很妥当,任务还没有进入队伍,这个线程就可能结束了。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2014-04-30 18:00 |显示全部楼层
回复 24# gaojl0728


    前面说得对,我准备把这个 thread_join_guard  去了,在后边手动 join

论坛徽章:
43
15-16赛季CBA联赛之四川
日期:2018-10-13 23:26:5015-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:36程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2014-04-30 18:54 |显示全部楼层
给你个阻塞队列的代码吧
https://github.com/windoze/Argos ... /concurrent_queue.h
你要高兴就把boost thread换成std thread,代码基本不用改

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2014-04-30 20:36 |显示全部楼层
windoze 发表于 2014-04-30 18:54
给你个阻塞队列的代码吧
https://github.com/windoze/Argos ... on/concurrent_queue ...


正在学习…………

两个问题:
1) 如何能够保证 simple_thread_pool 退出的时候能够保证 work_queue 中的任务没有遗留?

2) 你的 concurrent_queue 作为一个通用容器,为何去掉了 copy-constructor 和 copy-assignment operator?

在我看来,很简单就可以用如下手法实现的:
  1. struct concurrent_queue
  2. {
  3. //.....
  4. private:
  5.     concurrent_queue( concurrent_queue const& other, std::lock_guard<std::mutex> const& lc ) : /*do concrete copy here */ {}
  6. public:
  7.     concurrent_queue( concurrent_queue const& other ) : concurrent_queue( other, std::lock_guard<std::mutex>{other.the_mutex_} ) {}
  8. };
复制代码

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2014-04-30 21:31 |显示全部楼层
本帖最后由 lost_templar 于 2014-04-30 21:53 编辑

临时这么办了,虽然粗制滥造,但是总算解决了:
让主线程负责擦屁股。

  1.     struct simple_thread_pool
  2.     {
  3.         typedef std::function<void()>                                           function_type;
  4.         std::atomic_bool                                                        all_done_flag;
  5.         std::queue<function_type>                                               work_queue;
  6.         mutable std::mutex                                                      work_queue_mutex;
  7.         std::vector<std::thread>                                                thread_array;
  8.         simple_thread_pool( std::size_t max_threads_ = std::thread::hardware_concurrency() ) : all_done_flag{ false }
  9.         {
  10.             if ( !max_threads_ )
  11.                 max_threads_ = 2;
  12.             try
  13.             {
  14.                 for ( std::size_t index = 0; index != max_threads_; ++index )
  15.                     thread_array.push_back( std::thread{ &simple_thread_pool::work_loader, this } );
  16.             }
  17.             catch(...)
  18.             {
  19.                 all_done_flag = true;
  20.                 throw;
  21.             }
  22.         }

  23.         ~simple_thread_pool()
  24.         {
  25.             while ( true )
  26.             {
  27.                 function_type remaining_work = nullptr;
  28.                 {
  29.                     std::lock_guard<std::mutex> lg{ work_queue_mutex };
  30.                     if ( !work_queue.empty() )
  31.                     {
  32.                         remaining_work = work_queue.front();
  33.                         work_queue.pop();
  34.                     }
  35.                 }
  36.                 if ( remaining_work )
  37.                     remaining_work();
  38.                 else
  39.                     break;
  40.             }

  41.             all_done_flag = true;
  42.             std::for_each(  thread_array.begin(), thread_array.end(), [](std::thread& the_thread)  { if ( the_thread.joinable() ) the_thread.join(); } );
  43.         }

  44.         template< typename Function >
  45.         void submit_work( Function f_ )
  46.         {
  47.             std::lock_guard<std::mutex> lk{ work_queue_mutex };
  48.             work_queue.push( function_type{f_} );
  49.         }

  50.         void work_loader()
  51.         {
  52.             while ( ! all_done_flag )
  53.             {
  54.                 function_type current_work = nullptr;

  55.                 {
  56.                     std::lock_guard<std::mutex> lg{ work_queue_mutex };
  57.                     if ( !work_queue.empty() )
  58.                     {
  59.                         current_work = work_queue.front();
  60.                         work_queue.pop();
  61.                     }
  62.                 }

  63.                 if ( !current_work )
  64.                     current_work = [](){ std::this_thread::yield(); };

  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


复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

SACC2019中国系统架构师大会

【数字转型 架构演进】SACC2019中国系统架构师大会,7折限时优惠重磅来袭!
2019年10月31日~11月2日第11届中国系统架构师大会(SACC2019)将在北京隆重召开。四大主线并行的演讲模式,1个主会场、20个技术专场、超千人参与的会议规模,100+来自互联网、金融、制造业、电商等领域的嘉宾阵容,将为广大参会者提供一场最具价值的技术交流盛会。

限时七折期:2019年8月31日前


----------------------------------------

大会官网>>
  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP