设为首页收藏本站

ISO/IEC C++ China Unofficial

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1191|回复: 21

【Flying with Boost.asio ①】线程安全的任务队列

[复制链接]

8

主题

64

帖子

269

积分

超级版主

Rank: 8Rank: 8

威望
12
经验
169
贡献
12
发表于 2015-12-8 15:59:26 | 显示全部楼层 |阅读模式
本帖最后由 nadesico19 于 2015-12-8 22:15 编辑

实现一个线程安全的任务队列,一般来说可以使用 mutex & condition_variable 的组合。

不过,一向懒惰的本人首先想到的是 asio::io_service ,因为这已经是一个纯天然酿造(?)自带线程安全的任务队列,只需10行左右,即能色香味俱全:


  1. class AsyncWorker {
  2. public:
  3.     template <class Handler> void post(Handler&& handler) {
  4.         mIoService.post(std::forward<Handler>(handler));
  5.     }
  6.     void run() {
  7.         boost::asio::io_service::work keep_working(mIoService);
  8.         mIoService.run();
  9.     }
  10. private:
  11.     boost::asio::io_service mIoService;
  12. };
复制代码


试试效果:

  1. AsyncWorker worker;
  2. std::thread worker_thread1([&] { worker.run(); });
  3. std::thread worker_thread2([&] { worker.run(); });

  4. for (int i = 0; i < 100; i++) {
  5.     worker.post([=] { std::cout << i << std::endl; });
  6. }

  7. worker_thread1.join();
  8. worker_thread2.join();
复制代码


虽然 Boost.asio 为我们提供了非常不错的异步编程接口,然而在使用时却不可避免的会遇到阻塞处理,譬如文件读写(非平台依存的)以及数据库访问(虽然偶尔也会有好心人https://github.com/blackjack/booredis),这种情况下也显示出了任务队列的必要性。

在后续贴中本人将分享一下过去使用 aiso + boost.coroutine 配合任务队列实现全程异步式网络服务的小小经验。(轻噗)

评分

参与人数 1威望 +1 贡献 +1 收起 理由
岩川黑鬼 + 1 + 1 (。・ω・)ノ网络IO问题好评如潮。.

查看全部评分

回复

使用道具 举报

3

主题

20

帖子

202

积分

超级版主

mikonmikonmi

Rank: 8Rank: 8

威望
4
经验
170
贡献
4
发表于 2015-12-8 17:00:31 | 显示全部楼层
期待后续。
不过把阻塞IO一股脑委托给异步,窃以为不是特别好的第一感觉吧……

点评

本地文件只要不是涉及到好几百 M 的操作我觉得当同步做问题不大。  发表于 2015-12-9 11:33
对于阻塞时间较短、开销不大的处理,我倾向于直接在事件循环里做掉。这里的主题也就不涉及关于这个问题的trade off了,主要是想找找node+ES6的感觉www  发表于 2015-12-8 17:17
沿海征收头GAY骨
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
发表于 2015-12-8 20:58:13 | 显示全部楼层
围观

点评

比安博士也要写c艹的?  发表于 2015-12-8 22:17
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复

使用道具 举报

10

主题

108

帖子

473

积分

超级版主

RA2DIY 特别行政区行政长官

Rank: 8Rank: 8

威望
4
经验
354
贡献
3
发表于 2015-12-8 21:38:07 | 显示全部楼层
proactor 模式?

ヲ是传统的 reactor 党。

点评

整体结构上用的是Proactor,而Asynchronous Operation Processor部分说是用Reactor造的,搞得挺复杂www  发表于 2015-12-8 22:25
We will prevail!! www.lhmouse.com
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
发表于 2015-12-8 23:15:58 | 显示全部楼层
@nadesico19 很少用,基本操作还是会的。很在意编译速度的事情

点评

https://github.com/lhmouse/poseidon 求测下编译速度(构建方法在 README 里有)。  发表于 2015-12-9 00:32
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

10

主题

108

帖子

473

积分

超级版主

RA2DIY 特别行政区行政长官

Rank: 8Rank: 8

威望
4
经验
354
贡献
3
发表于 2015-12-9 00:31:36 | 显示全部楼层
本帖最后由 LH_Mouse 于 2015-12-9 02:40 编辑

ヲ提一下ヲ在 poseidon 里的思路吧。

任务队列的想法是对的,不过 asio 嘛……基本可以呵呵了。

ヲ提出的类似是 ASMP 的架构,可以称为 asymmetric multi-threading。
特点就是主消息线程有一个,epoll 线程有一个,MySQL 线程有一堆,计时器线程有一个。
每个线程都有一个队列(这里需要用 mutex 和 condition variable)。
因为主消息线程只有一个,所以只要业务逻辑全部丢在主消息线程,就可以不用锁。
这里就能看出采用 Reactor 模式的一个优势:对网络消息的解码(反序列化)完全可以交予 epoll 线程,不需要动用主消息线程的时间片。

=====================
补充一点:
主消息线程的队列实现类似于 map<weak_ptr<void>, deque<shared_ptr<message>>>。
这里的 key 用于确保同一个 session、定时器、event 发出的消息的有序性。
第一,因为 MySQL 没有异步接口,必须提供异步机制,这里采用 setjmp-longjmp 实现协程。因此消息的有序性非常重要。
第二,可以通过 iterator->first.expired() 识别掉线的 session 或已删除的定时器等。




点评

((o≧Д≦o))ノ☆・゚: *スゴ杉*:゚!!!好完整的解决方案。主线程无锁、消息解码都是不错的考虑,就是setjmp-longjmp遇到异常安全感觉有点怕怕w  发表于 2015-12-9 09:26
We will prevail!! www.lhmouse.com
回复 支持 反对

使用道具 举报

10

主题

108

帖子

473

积分

超级版主

RA2DIY 特别行政区行政长官

Rank: 8Rank: 8

威望
4
经验
354
贡献
3
发表于 2015-12-9 11:26:24 | 显示全部楼层
本帖最后由 LH_Mouse 于 2015-12-9 11:29 编辑

@nadesico19  
setjmp-longjmp 只用于协程切换。如果协程里面丢异常出来,用 exception 吃掉然后塞进 promise 里。

大概看起来是这样:
  1. const auto promise = make_shared<Promise>();
  2. post_async_message(promise,
  3.   [&]{
  4.     try { // This 'try ... catch' is for exposition only.
  5.           // You ain't gonna need to write it yourself.
  6.       do_something();
  7.       promise->set_success();
  8.     } catch(..){
  9.       promise->set_exception(current_exception());
  10.     }
  11.   });
  12. MessageLoop::yield(promise);
  13. promise->check_and_rethrow(); // Rethrow the exception, should one be caught.
  14.                               // If the message times out this function effectively
  15.                               // throws an exception indicating the message has timed out.
  16. // No exception has been caught. We are done here.
复制代码

点评

看上去不错!Σ(・艸・○)ェ!!  发表于 2015-12-9 14:14
We will prevail!! www.lhmouse.com
回复 支持 反对

使用道具 举报

0

主题

10

帖子

45

积分

新手上路

Rank: 1

威望
1
经验
32
贡献
1
发表于 2015-12-9 11:31:56 | 显示全部楼层
棒棒棒
回复

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
发表于 2015-12-9 12:00:50 | 显示全部楼层
@LH_Mouse  编译无力,看了下编译工具也是跪了,makefile渣表示膜拜
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

1

主题

16

帖子

73

积分

超级版主

Rank: 8Rank: 8

威望
0
经验
57
贡献
0
发表于 2015-12-9 12:58:47 | 显示全部楼层
LH_Mouse 发表于 2015-12-9 00:31
ヲ提一下ヲ在 poseidon 里的思路吧。

任务队列的想法是对的,不过 asio 嘛……基本可以呵呵了。

主线程无锁, 矮油不错

点评

><  发表于 2015-12-9 23:20
回复 支持 反对

使用道具 举报

10

主题

108

帖子

473

积分

超级版主

RA2DIY 特别行政区行政长官

Rank: 8Rank: 8

威望
4
经验
354
贡献
3
发表于 2015-12-9 13:22:16 | 显示全部楼层
@moecmks
你系统难道是 centos?
We will prevail!! www.lhmouse.com
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
发表于 2015-12-9 22:21:09 | 显示全部楼层
本帖最后由 moecmks 于 2015-12-9 22:22 编辑

@LH_Mouse
win = =。

点评

比安博士竟然不是用自己写的OS,差评23333  发表于 2015-12-9 22:26
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

10

主题

108

帖子

473

积分

超级版主

RA2DIY 特别行政区行政长官

Rank: 8Rank: 8

威望
4
经验
354
贡献
3
发表于 2015-12-9 23:19:37 | 显示全部楼层

ナ明显是 Linux specific!
We will prevail!! www.lhmouse.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|ISO/IEC C++ China Unofficial    

GMT+8, 2017-10-19 20:52 , Processed in 0.077535 second(s), 29 queries , Xcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表