Boost::asio io_service 实现分析
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 实现代码的基本类结构:
l Io_servie是接口类,为实现跨平台,采用了策略模式,所有接口均有impl_type实现。根据平台不同impl_type分为
n win_iocp_io_service Win版本的实现,这里主要分析Linux版本。
n task_io_service 非win平台下的实现,其代码结构为:
u detail/task_io_service_fwd.hpp 简单声明task_io_service名称
u detail/task_io_service.hpp 声明task_io_service的方法和属性
u detail/impl/task_io_service.ipp 具体实现文件
u 队列中的任务类型为opertioan,原型其实是typedef task_io_service_operation operation,其实现文件在detail/task_io_service_operation.hpp中,当队列中的任务被执行时,就是task_io_service_operation:: complete被调用的时候。
Io_servie::Post方法的实现
Post向队列中投递任务,然后激活空闲线程执行任务。其实现流程如下:
l Post接收handler作为参数,实际上是个仿函数,通过此仿函数构造出completion_handler对象,completion_handler继承自operation。然后调用post_immediate_completion。
l post_immediate_completion首先将outstanding_work_增加,然后调用post_deferred_completion。
l post_deferred_completion首先加锁将任务入列,然后调用wake_one_thread_and_unlock
l wake_one_thread_and_unlock尝试唤醒当前空闲的线程,其实现中特别之处在于,若没有空闲线程,但是有线程在执行task->run,即阻塞在epoll_wait上,那么先中断epoll_wait执行任务队列完成后再执行epoll_wait。
l first_idle_thread_维护了所有当前空闲线程,实际上使用了Leader/Follower模式,每次唤醒时只唤醒空闲线程的第一个。
Io_servie::run方法的实现
Run方法执行队列中的所有任务,直到任务执行完毕。
l run方法首先构造一个idle_thread_info,和first_idle_thread_类型相同,即通过first_idle_thread_将所有线程串联起来,它这个串联不是立即串联的,当该线程无任务可做是加入到first_idle_thread_的首部,有任务执行时,从first_idle_thread_中断开。这很正常,因为first_idle_thread_维护的是当前空闲线程。
l 加锁,循环执行do_one方法,直到do_one返回false
l do_one每次执行一个任务。首先检查队列是否为空,若空将此线程追加到first_idle_thread_的首部,然后阻塞在条件变量上,直到被唤醒。
l 当被唤醒或是首次执行,若stopped_为true(即此时stop方法被调用了),返回0
l 队列非空,pop出一个任务,检查队列无任务那么简单的解锁,若仍有,调用wake_one_thread_and_unlock尝试唤醒其他空闲线程执行。然后执行该任务,返回1.
l 实际上在执行队列任务时有一个特别的判断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。很是巧妙。!!!实际上就是因为有了这个reactor,它才叫io_servie,否则就是一个纯的任务队列了。
l Run方法的原则是:
n 有任务立即执行任务,尽量使所有的线程一起执行任务
n 若没有任务,阻塞在epoll_wait上等待io事件
n 若有新任务到来,并且没有空闲线程,那么先中断epoll_wait,先执行任务
n 若队列中有任务,并且也需要epoll_wait监听事件,那么非阻塞调用epoll_wait(timeout字段设置为0),待任务执行完毕在阻塞在epoll_wait上。
n 几乎对线程的使用上达到了极致。
n 从这个函数中可以知道,在使用ASIO时,io_servie应该尽量多,这样可以使其epoll_wait占用的时间片最多,这样可以最大限度的响应IO事件,降低响应时延。但是每个io_servie::run占用一个线程,所以io_servie最佳应该和CPU的核数相同。
Io_servie::stop的实现
l 加锁,调用stop_all_threads
l 设置stopped_变量为true,遍历所有的空闲线程,依次唤醒
l task_interrupted_设置为true,调用task_的interrupt方法
l task_的类型为reactor,在run方法中已经做了分析
l
Boost::asio io_service 实现分析的更多相关文章
- 网络库crash以及boost asio strand dispath分析
最近在做服务器的稳定性的相关测试,服务器的网络底层使用的是boost asio,然后自己做的二次封装以更好的满足需求. 服务器昨天晚上发现crash了一次,之前测试了将近半个多月,有一次是莫名的退出了 ...
- boost asio io_service学习笔记
构造函数 构造函数的主要动作就是调用CreateIoCompletionPort创建了一个初始iocp. Dispatch和post的区别 Post一定是PostQueuedCompletionSta ...
- boost::asio::io_service::定时器任务队列
使用io_service和定时器写的一个同步和异步方式的任务队列 #pragma once #include <string> #include <iostream> #inc ...
- 概念理解:boost::asio::io_service
IO模型 io_service对象是asio框架中的调度器,所有异步io事件都是通过它来分发处理的(io对象的构造函数中都需要传入一个io_service对象). asio::io_service i ...
- boost::asio::io_service类
大部分使用Boost.Asio编写的代码都会使用几个io_service的实例.io_service是这个库里面最重要的类:它负责和操作系统打交道,等待所有异步操作的结束,然后为每一个异步操作调用其完 ...
- boost.asio源码剖析(三) ---- 流程分析
* 常见流程分析之一(Tcp异步连接) 我们用一个简单的demo分析Tcp异步连接的流程: #include <iostream> #include <boost/asio.hpp& ...
- boost.asio系列——io_service
IO模型 io_service对象是asio框架中的调度器,所有异步io事件都是通过它来分发处理的(io对象的构造函数中都需要传入一个io_service对象). asio::io_service i ...
- boost asio 学习(一)io_service的基础
原文 http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio/ 编译环境 b ...
- boost.asio源码剖析(五) ---- 泛型与面向对象的完美结合
有人说C++是带类的C:有人说C++是面向对象编程语言:有人说C++是面向过程与面向对象结合的语言.类似的评论网上有很多,虽然正确,却片面,是断章取义之言. C++是实践的产物,C++并没有为了成为某 ...
随机推荐
- SSH框架入门学习之二(spring)
Spring也是一个开源框架,我在学习Spring的时候,认为最重要的几点是:IOC(控制反转).AOP(面向切面)和容器概念. 详细的教程还请大家去看网上的视频,这里贴一个小Demo以供学习. (前 ...
- ThinkPHP - F函数,更新配置文件
Html代码: <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&quo ...
- C++,对象的 =赋值 以及 复制构造函数赋值
1. C++默认实现了 = 号赋值:operator=只要将一个对象的内容的内容逐位复制给另外一个对象即可. 2. C++默认实现了复制构造函数:同样,只要将一个对象的内容的内容逐位复制给另外一个对象 ...
- XCode 6 出现 no identity found: Command /usr/bin/codesign failed with exit code 1 解决方法汇总
1, 解决办法,进入开发者账号重建一个 Provisioning Profiles(或配套证书) 文件,把证书添加正确就可以了 (应该是最有效的) 2, 将p12文件重新安装下 3, 在 iPhone ...
- CentOS6.5下VNC Server远程桌面配置详解
参考文献: (总结)CentOS Linux下VNC Server远程桌面配置详解 远程桌面连接工具VNC——license Key 我的下载地址为 太平洋下载 VNC连接黑屏的问题 centos 6 ...
- (Problem 15)Lattice paths
Starting in the top left corner of a 22 grid, and only being able to move to the right and down, the ...
- hibernate对应的annocation版本
Hibernate Compatibility Matrix Package Version Core Annotations EntityManager Validator Search Shard ...
- LGPL与闭源程序
最近一直在学习 Qt.Qt 有两个许可证:LGPL 和商业协议.这两个协议在现在的 Qt 版本中的代码是完全一致的(潜在含义是,Qt 的早期版本,商业版的 Qt 通常包含有一些开源版本所没有的库,比如 ...
- vc++窗口的创建过程(MFC消息机制的经典文章)
一.什么是窗口类 在Windows中运行的程序,大多数都有一个或几个可以看得见的窗口,而在这些窗口被创建起来之前,操作系统怎么知道该怎样创建该窗口,以及用户操作该窗口的各种消息交给谁处理呢?所以VC ...
- 一步一步重写 CodeIgniter 框架 (11) —— 使用 CodeIgniter 函数库
在完成了CI框架的类库扩展后,很自然我们就会想到函数库的扩展.函数库的扩展在 CI 中称为 helper 函数与类有不同的地方,它不能继承,只能覆盖或者添加新的函数,或者直接完全新定义的一组函数. 由 ...