以当前最新版本的boost为例(1.53.0,之后的代码也是以1.53.0为准)。

ASIO Examples:http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/examples.html
io_service在ASIO中有着举足轻重的地位置如果对io_service的实现不感兴趣可以选择性无视这篇文章。在开始说io_service之前,先介绍一下ASIO给我们提供的可用于TCP服务器开发的组件。
















boost::asio::ip::tcp::acceptor 用于监听与接受连接的类。
boost::asio::ip::tcp::socket 套接字,提供同步/异步IO方法,一个socket对象面向一个客户端连接。
boost::asio::deadline_timer 计时器,提供同步/异步计时功能并在计时结束之后回调到一个函数。

io_service的工作方式

把io_service想象为一个Worker Pool,也可以把它当作一个IO队列,他是一个联系用户和ASIO核心实现的类。如果你看过ASIO的例子或者用过ASIO,在构造上面表格中的对象时,往往需要给它们传递一个io_service对象,因为io_service担任的是一个Worker Pool的作用,这些组件的任何IO操作都会通过io_service.post()方法去投递一个任务。

为了更直观地看到io_service的作用,来一段异步定时器(deadline_timer)工作的代码:

[cpp]

#include <boost/bind.hpp> //for std::bind()

#include <boost/asio.hpp>

int main()
{
void on_expired();

boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::milliseconds(3000));
timer.async_wait(boost::bind(on_expired, boost::asio::placeholders::error));
io_service.run();

return 0;

}

void on_expired(const boost::system::error_code& error)
{
if (!error)
{
std::cout << "timer expired." << std::endl;
}
}
[/cpp]

上面代码演示了一个异步定时器的工作流程:
1.定义一个io_service对象。
2.定义一个deadline_timer对象,并把io_service对象作为唯一参数传递给它。
3.使用expires_from_now()方法设置一个以当前时间为起始点的超时时间。
4.调用deadline_timer的async_wait()方法使定时器进入等待。
5.调用io_service的run()方法。

第4步调用async_wait()方法之后,deadline_timer的内部就做了一些和io_service打交道的事,它实则是向io_service提交了一个异步任务,io_service会把它放到队列里。第5步我们调用run()方法时,io_service就开始了它的工作,并把队列中的任务进行处理。

io_service用例图:
uml_io_service

这个用例图展示了io_service的工作方式:
1.用户的应用程序提交一个操作。
2.操作转发给io_service,告诉它我有一个异步操作可能要执行,此时io_service便会把该操作放入一个队列里。
3.调用run()方法启动io_service。
4.io_service启动后,会把队列中的操作提交给操作系统,相当于一个联系了用户和操作系统的媒介。
5.操作系统把执行结果反馈给io_service,io_service会根据结果构造一个boost::system::error_code对象并回调给用户,通过该对象可获知所投递操作的执行结果。

流程很简单,从我们的应用程序逐层向下,完成之后再逐层向上反馈。但是,我们看到的其实只是冰山一角。ASIO是一个网络库,除了给我们提供了定时器这类开发组件之外,更重要的是它的网络通信功能。ASIO提供的网络通信功能,不仅封装了操作系统提供的socket api,同时也用自己的思想把不同平台的网络通信模型封装了起来。下面我们来深入io_service,揭开其面纱。

io_service的跨平台策略

考虑到在多平台下的实现细节,io_service可谓是做了不少功夫。要根据不同平台提供的api去设计一个统一的框架提供给用户,而且用户不必关心其实现细节,除了工程庞大之外,也必须要有一个良好的框架。我们从io_service的源码入手,探讨它如何去适应不同平台的实现。(推荐用Source Insight, Sublime Text 2或VC编辑器阅读源码)。

由io_service.run()开始,先转到run()的定义:

[cpp]std::sizet s = impl.run(ec);[/cpp]

该方法实则上是调用了impl_对象的run()方法,看起来是ioservice在impl的基础上封装了一层,impl_是ioservice的成员,不难看出,impl担任了一个实现功能细节的角色。在ioservice类的声明中,找到impl的声明:

[cpp]
// The implementation.
impltype& impl;
[/cpp]

然后是impl_type类型的定义:

[cpp]
typedef detail::io_service_impl impl_type;
[/cpp]

原来impl_type的原本类型是detail::io_service_impl,实质上它是由宏来决定其最终类型。转到定义可以发现:

[cpp]

#if defined(BOOST_ASIO_HAS_IOCP)
namespace detail { typedef win_iocp_io_service io_service_impl; }

#else
namespace detail { typedef task_io_service io_service_impl; }

#endif
[/cpp]

上面代码很清晰可以看到,如果定义了BOOST_ASIO_HAS_IOCP这个宏,那么io_service_impl的类型就是win_iocp_io_service,否则就是task_io_service. 如此说来,io_service_impl这个类型完全是由BOOST_ASIO_HAS_IOCP宏来决定的。跟踪一下这个宏,看它如何定义:

[cpp]
// Windows: IO Completion Ports.

#if defined(BOOST_WINDOWS) || defined(CYGWIN)

if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)

if !defined(UNDER_CE)

if !defined(BOOST_ASIO_DISABLE_IOCP)

define BOOST_ASIO_HAS_IOCP 1

endif // !defined(BOOST_ASIO_DISABLE_IOCP)

endif // !defined(UNDER_CE)

endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)

#endif // defined(BOOST_WINDOWS) || defined(CYGWIN)

// Linux: epoll, eventfd and timerfd.

#if defined(linux)

include <linux/version.h>

if !defined(BOOST_ASIO_DISABLE_EPOLL)

if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)

define BOOST_ASIO_HAS_EPOLL 1

endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)

endif // !defined(BOOST_ASIO_DISABLE_EVENTFD)

if !defined(BOOST_ASIO_DISABLE_EVENTFD)

if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)

define BOOST_ASIO_HAS_EVENTFD 1

endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)

endif // !defined(BOOST_ASIO_DISABLE_EVENTFD)

if defined(BOOST_ASIO_HAS_EPOLL)

if (GLIBC > 2) || (GLIBC == 2 && GLIBC_MINOR >= 8)

define BOOST_ASIO_HAS_TIMERFD 1

endif // (GLIBC > 2) || (GLIBC == 2 && GLIBC_MINOR >= 8)

endif // defined(BOOST_ASIO_HAS_EPOLL)

#endif // defined(linux)
[/cpp]

如果在Windows或者CYGWIN环境并且IOCP未被禁用的情况下,那么ASIO的网络模型就会被定义为IOCP;而在linux下,则有epoll, eventfd, timerfd三种情况,但结合io_service_impl的定义,可以发现除了BOOST_ASIO_HAS_IOCP在打开时io_service_impl被定义为win_iocp_io_service之外,其它情况都是task_io_service. 因此可以把ASIO归纳为只有两种实现,分别是win_iocp_io_service和task_io_service. 而在ioservice中impl成员的最终类型,也只有这两种。无论采用了哪种模型,ioservice暴露的方法都一样,他们的具体实现都必须转给impl去做。

service_level_table

这一章简要说了一下io_service的组成和工作机制,接着将介绍io_service的Proactor框架实现和io_service的service管理。因为这一章的内容和接下来要说的内容关联不算太大,而且说到Proactor实现部分比较长。其实下一章内容写的差不多了,不过还要写几天再发,先发这篇短的。