io_service类多线程
你应该已经发现大部分使用Boost.Asio编写的代码都会使用几个io_service的实例。io_service是这个库里面
最重要的类;它负责和操做系统打交道,等待全部异步操做的结束,而后为每个异步操做调用其完成处
理程序。
若是你选择用同步的方式来建立你的应用,你则不须要考虑我将在这一节向你展现的东西。 你有多种不一样
的方式来使用io_service。在下面的例子中,咱们有3个异步操做,2个socket链接操做和一个计时器等待操
做:
有一个io_service实例和一个处理线程的单线程例子:
io_service service; // 全部socket操做都由service来处理
ip::tcp::socket sock1(service); // all the socket operations are handled by service
ip::tcp::socket sock2(service); 异步
sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
service.run();
有一个io_service实例和多个处理线程的多线程例子:
io_service service;
ip::tcp::socket sock1(service);
ip::tcp::socket sock2(service);
sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 5; ++i)
boost::thread( run_service);
void run_service()
{
service.run();
}
有多个io_service实例和多个处理线程的多线程例子:
io_service service[2];
ip::tcp::socket sock1(service[0]);
ip::tcp::socket sock2(service[1]);
sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service[0], boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 2; ++i)
boost::thread( boost::bind(run_service, i));socket
void run_service(int idx)
{
service[idx].run();
}
首先,要注意你不能拥有多个io_service实例却只有一个线程。下面的代码片断没有任何意义:
for ( int i = 0; i < 2; ++i)
service[i].run();
上面的代码片断没有意义是由于service[1].run()须要service[0].run()先结束。所以,全部由service[1]处理的
异步操做都须要等待,这显然不是一个好主意。
在前面的3个方案中,咱们在等待3个异步操做结束。为了解释它们之间的不一样点,咱们假设:过一会操做1
完成,而后接着操做2完成。同时咱们假设每个完成处理程序须要1秒钟来完成执行。
在第一个例子中,咱们在一个线程中等待三个操做所有完成,第1个操做一完成,咱们就调用它的完成处理
程序。尽管操做2紧接着完成了,可是操做2的完成处理程序须要在1秒钟后,也就是操做1的完成处理程序
完成时才会被调用。
第二个例子,咱们在两个线程中等待3个异步操做结束。当操做1完成时,咱们在第1个线程中调用它的完成
处理程序。当操做2完成时,紧接着,咱们就在第2个线程中调用它的完成处理程序(当线程1在忙着响应操
做1的处理程序时,线程2空闲着而且能够回应任何新进来的操做)。
在第三个例子中,由于操做1是sock1的connect,操做2是sock2的connect,因此应用程序会表现得像第二
个例子同样。线程1会处理sock1 connect操做的完成处理程序,线程2会处理sock2的connect操做的完成处
理程序。然而,若是sock1的connect操做是操做1,deadline_timer t的超时操做是操做2,线程1会结束正
在处理的sock1 connect操做的完成处理程序。于是,deadline_timer t的超时操做必须等sock1 connect操
做的完成处理程序结束(等待1秒钟),由于线程1要处理sock1的链接处理程序和t的超时处理程序。async
下面是你须要从前面的例子中学到的:
第一种状况是很是基础的应用程序。由于是串行的方式,因此当几个处理程序须要被同时调用时,你
一般会遇到瓶颈。若是一个处理程序须要花费很长的时间来执行,全部随后的处理程序都不得不等
待。
第二种状况是比较适用的应用程序。他是很是强壮的——若是几个处理程序被同时调用了(这是有可
能的),它们会在各自的线程里面被调用。惟一的瓶颈就是全部的处理线程都很忙的同时又有新的处
理程序被调用。然而,这是有快速的解决方式的,增长处理线程的数目便可。
第三种状况是最复杂和最难理解的。你只有在第二种状况不能知足需求时才使用它。这种状况通常就
是当你有成千上万实时(socket)链接时。你能够认为每个处理线程(运行io_service::run()的线
程)有它本身的select/epoll循环;它等待任意一个socket链接,而后等待一个读写操做,当它发现这
种操做时,就执行。大部分状况下,你不须要担忧什么,惟一你须要担忧的就是当你监控的socket数
目以指数级的方式增加时(超过1000个的socket)。在那种状况下,有多个select/epoll循环会增长应
用的响应时间。
若是你以为你的应用程序可能须要转换到第三种模式,请确保监听操做的这段代码(调用io_service::run()
的代码)和应用程序其余部分是隔离的,这样你就能够很轻松地对其进行更改。tcp