Boost库之asio io_service以及run、run_one、poll、poll_one区别

原文:http://blog.csdn.net/byxdaz/article/details/71088812

一、io_service的作用

io_servie 实现了一个任务队列,这里的任务就是void(void)的函数。Io_servie最常用的两个接口是post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。Io_service是完全线程安全的队列。

二、Io_servie的接口

提供的接口有run、run_one、poll、poll_one、stop、reset、dispatch、post,最常用的是run、post、stop

三、Io_servie 实现代码的基本类结构:

Io_servie是接口类,为实现跨平台,采用了策略模式,所有接口均有impl_type实现。根据平台不同impl_type分为

win_iocp_io_service Win版本的实现,这里主要分析Linux版本。

task_io_service 非win平台下的实现,其代码结构为:

detail/task_io_service_fwd.hpp 简单声明task_io_service名称

detail/task_io_service.hpp 声明task_io_service的方法和属性

detail/impl/task_io_service.ipp 具体实现文件

队列中的任务类型为opertioan,原型其实是typedef task_io_service_operation operation,其实现文件在detail/task_io_service_operation.hpp中,当队列中的任务被执行时,就是task_io_service_operation:: complete被调用的时候。

四、Dispatch和post的区别

Post一定是PostQueuedCompletionStatus并且在GetQueuedCompletionStatus 之后执行。

Dispatch会首先检查当前thread是不是io_service.run/runonce/poll/poll_once线程,如果是,则直接运行。

五、Io_servie::run方法的实现

Run方法执行队列中的所有任务,直到任务执行完毕。

run方法首先构造一个idle_thread_info,和first_idle_thread_类型相同,即通过first_idle_thread_将所有线程串联起来,它这个串联不是立即串联的,当该线程无任务可做是加入到first_idle_thread_的首部,有任务执行时,从first_idle_thread_中断开。这很正常,因为first_idle_thread_维护的是当前空闲线程。

加锁,循环执行do_one方法,直到do_one返回false

do_one每次执行一个任务。首先检查队列是否为空,若空将此线程追加到first_idle_thread_的首部,然后阻塞在条件变量上,直到被唤醒。

当被唤醒或是首次执行,若stopped_为true(即此时stop方法被调用了),返回0

队列非空,pop出一个任务,检查队列无任务那么简单的解锁,若仍有,调用wake_one_thread_and_unlock尝试唤醒其他空闲线程执行。然后执行该任务,返回1.

实际上在执行队列任务时有一个特别的判断if (o ==&task_operation_),那么将会执行task_->run,task_变量类型为reactor,在linux平台实现为epoll_reactor,实现代码文件为detail/impl/epoll_reactor.ipp,run方法实际上执行的是epoll_wait,run阻塞在epoll_wait上等待事件到来,并且处理完事件后将需要回调的函数push到io_servie的任务队列中,虽然epoll_wait是阻塞的,但是它提供了interrupt函数,该interrupt是如何实现的呢,它向epoll_wait添加一个文件描述符,该文件描述符中有8个字节可读,这个文件描述符是专用于中断epoll_wait的,他被封装到select_interrupter中,select_interrupter实际上实现是eventfd_select_interrupter,在构造的时候通过pipe系统调用创建两个文件描述符,然后预先通过write_fd写8个字节,这8个字节一直保留。在添加到epoll_wait中采用EPOLLET水平触发,这样,只要select_interrupter的读文件描述符添加到epoll_wait中,立即中断epoll_wait。

Run方法的原则是:

有任务立即执行任务,尽量使所有的线程一起执行任务

若没有任务,阻塞在epoll_wait上等待io事件

若有新任务到来,并且没有空闲线程,那么先中断epoll_wait,先执行任务

若队列中有任务,并且也需要epoll_wait监听事件,那么非阻塞调用epoll_wait(timeout字段设置为0),待任务执行完毕在阻塞在epoll_wait上。

几乎对线程的使用上达到了极致。

从这个函数中可以知道,在使用ASIO时,io_servie应该尽量多,这样可以使其epoll_wait占用的时间片最多,这样可以最大限度的响应IO事件,降低响应时延。但是每个io_servie::run占用一个线程,所以io_servie最佳应该和CPU的核数相同。

六、Io_servie::stop的实现

加锁,调用stop_all_threads

设置stopped_变量为true,遍历所有的空闲线程,依次唤醒

task_interrupted_设置为true,调用task_的interrupt方法。

七、reset和stop

文档中reset的解释是重置io_service以便下一次调用。

当 run,run_one,poll,poll_one是被stop掉导致退出,或者由于完成了所有任务(正常退出)导致退出时,在调用下一次 run,run_one,poll,poll_one之前,必须调用此函数。reset不能在run,run_one,poll,poll_one正在运行时调用。如果是消息处理handler(用户代码)抛出异常,则可以在处理之后直接继续调用io.run,run_one,poll,poll_one。

八、run,run_one,poll,poll_one的区别

run其实就是一直循环执行do_one,并且是以阻塞方式进行的(参数为true),而run_one同样是以阻塞方式进行的,但只执行一次do_one;poll和run几乎完全相同,只是它是以非阻塞方式执行do_one(参数为false),poll_one是以非阻塞方式执行一次do_one。

run,run_one,及poll,poll_one的实现代码,如下:

[cpp] view plaincopy
  1. // Run the event loop until stopped or no more work.
  2. size_t run(boost::system::error_code& ec)
  3. {
  4. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  5. {
  6. stop();
  7. ec = boost::system::error_code();
  8. return 0;
  9. }
  10. call_stack<win_iocp_io_service>::context ctx(this);
  11. size_t n = 0;
  12. while (do_one(true, ec))
  13. if (n != (std::numeric_limits<size_t>::max)())
  14. ++n;
  15. return n;
  16. }
  17. // Run until stopped or one operation is performed.
  18. size_t run_one(boost::system::error_code& ec)
  19. {
  20. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  21. {
  22. stop();
  23. ec = boost::system::error_code();
  24. return 0;
  25. }
  26. call_stack<win_iocp_io_service>::context ctx(this);
  27. return do_one(true, ec);
  28. }
  29. // Poll for operations without blocking.
  30. size_t poll(boost::system::error_code& ec)
  31. {
  32. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  33. {
  34. stop();
  35. ec = boost::system::error_code();
  36. return 0;
  37. }
  38. call_stack<win_iocp_io_service>::context ctx(this);
  39. size_t n = 0;
  40. while (do_one(false, ec))
  41. if (n != (std::numeric_limits<size_t>::max)())
  42. ++n;
  43. return n;
  44. }
  45. // Poll for one operation without blocking.
  46. size_t poll_one(boost::system::error_code& ec)
  47. {
  48. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  49. {
  50. stop();
  51. ec = boost::system::error_code();
  52. return 0;
  53. }
  54. call_stack<win_iocp_io_service>::context ctx(this);
  55. return do_one(false, ec);
  56. }
  57. do_one的函数原型
  58. size_t do_one(bool block, boost::system::error_code& ec)
  59. {
  60. BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, &completion_key, &overlapped, block ? timeout : 0);
  61. }

Boost库之asio io_service以及run、run_one、poll、poll_one区别相关推荐

  1. boost库使用—asio库

    boost库使用-asio库 **** 一.boost库asio简介 Boost Asio ( asynchronous input and output)关注异步输入输出.Boost Asio库提供 ...

  2. boost asio io_service学习笔记

    转自:http://hi.baidu.com/jrckkyy/blog/item/e86835d61e60722506088b6a.html 构造函数 构造函数的主要动作就是调用CreateIoCom ...

  3. boost::asio::io_service的stop()和reset()和stopped()函数

    ◆boost::asio::io_service使用时的注意事项: ①请让boost::asio::io_service和boost::asio::io_service::work搭配使用. ②想让e ...

  4. boost库中优秀的网络库asio

    文章目录 一.须知 二.ASIO 三.我们将从研究同步操作开始 四.当使用异步操作时,会发生不同的事件序列 五.Proactor模型 六.常用内容 七.C++ 建立本地网络服务器 (Boost.Asi ...

  5. 【Boost】boost库asio详解2——io_service::run函数无任务时退出的问题

    io_service::work类可以使io_service::run函数在没有任务的时候仍然不返回,直至work对象被销毁. [cpp] view plaincopy print? void tes ...

  6. 【Boost】boost库asio详解1——io_service::run函数无任务时退出的问题

    io_service::work类可以使io_service::run函数在没有任务的时候仍然不返回,直至work对象被销毁. [cpp] view plain copy  print? void t ...

  7. 【Boost】boost库asio详解3——io_service作为work pool

    无论如何使用,都能感觉到使用boost.asio实现服务器,不仅是一件非常轻松的事,而且代码很漂亮,逻辑也相当清晰,这点上很不同于ACE. 使用io_service作为处理工作的work pool,可 ...

  8. 【Boost】boost库asio详解2——strand与io_service区别

    [cpp] view plain copy  print? namespace { // strand提供串行执行, 能够保证线程安全, 同时被post或dispatch的方法, 不会被并发的执行. ...

  9. 【Boost】boost库asio详解1——strand与io_service区别

    namespace {// strand提供串行执行, 能够保证线程安全, 同时被post或dispatch的方法, 不会被并发的执行. // io_service不能保证线程安全boost::asi ...

最新文章

  1. 使用overlap-add方法计算两个信号的卷积示例(在频域计算卷积)
  2. 使用坚果云同步SVN服务器数据
  3. 移动设备的界面设计尺寸
  4. STM32中断与事件
  5. SQL索引碎片整理脚本
  6. 如何在jQuery的SELECT元素中选择特定选项?
  7. 解决Rails找不到Javascript的错误
  8. 斯坦福NLP名课带学详解 | CS224n 第1讲 - NLP介绍与词向量初步(NLP通关指南·完结)
  9. mysql中as是什么意思_数据库中as是什么意思
  10. 【洛谷P2123】皇后游戏
  11. 【HDU 5755】Gambler Bo(高斯消元)
  12. pms解析--未完待续
  13. 毕业几年LINUX 驱动研发工作心得分享
  14. matlab颜色直方图特征提取,灰度直方图特征提取的Matlab实现
  15. js知识点 掘金_掘金js
  16. 谱本征正交分解 (SPOD)附matlab代码
  17. iphone SLO-MO, TIME-LAPSE, VIDEO,PANO
  18. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java手游账号交易系统u2741
  19. 如何禁止访问一个网站??
  20. java工具类怎么写_常用的Java工具类——十六种

热门文章

  1. linux磁盘分配方案,安装Linux系统磁盘分配方案.doc
  2. Spring MVC控制器的单元测试:“普通”控制器
  3. video.min.js php,使用flv.js与video.js做一个视频直播效果
  4. php 360 极速模式,如何让360浏览器默认使用极速模式
  5. linux 文件拷贝io,NIO拷贝文件真的比IO拷贝文件效率高?
  6. java使用重绘实现拖动_原生JS使用Canvas实现拖拽式绘图功能
  7. 结棍!Spring 支持 PHP 了!?
  8. 一款实用可行的支付系统,专供互联网企业使用,赶紧收藏了!
  9. 最强代码生成器平台,杀疯了!
  10. 皮一皮:狭路相逢勇者胜...