这个问题有一定程度的不确定性,就好像有多个io_service
需要对象。我无法在其中找到任何内容参考 http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference.html文档或概述SSL http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/overview/ssl.html and UNIX 域套接字 http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/overview/posix/local.html规定单独的io_service
对象。无论如何,这里有一些选择:
Single io_service
:
尝试使用单个io_service
.
如果您没有直接处理io_service
对象,但你有一个 Boost.Asio I/O 对象的句柄,例如一个套接字,然后是一个关联的句柄io_service
可以通过调用获取对象socket.get_io_service() http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/basic_stream_socket/get_io_service.html.
每使用一个线程io_service
:
如果有多个io_service
需要对象,然后为每个对象指定一个线程io_service
。这种方法被用在Boost.Asio的HTTP服务器2 http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/http/server2/例子。
boost::asio::io_service service1;
boost::asio::io_service service2;
boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &service1));
service2.run();
threads.join_all();
这种方法的一个后果是它可能需要应用程序做出线程安全保证。例如,如果service1
and service2
两者都有调用的完成处理程序message_processor.process()
, then message_processor.process()
需要是线程安全的或以线程安全的方式调用。
Poll io_service
:
io_service http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/io_service.html提供非阻塞替代方案run()
。然而io_service::run() http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/io_service/run/overload1.html将阻塞直到所有工作完成,io_service::poll() http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/io_service/poll/overload1.html将运行准备运行且不会阻塞的处理程序。这允许单个线程在多个线程上执行事件循环io_service
对象:
while (!service1.stopped() &&
!service2.stopped())
{
std::size_t ran = 0;
ran += service1.poll();
ran += service2.poll();
// If no handlers ran, then sleep.
if (0 == ran)
{
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
}
为了防止在没有准备运行的处理程序时出现紧忙循环,可能值得添加睡眠。请注意,此睡眠可能会在事件的整体处理中引入延迟。
将处理程序转移到单个io_service
:
一种有趣的方法是使用strand http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/io_service__strand.html将完成处理程序传输到单个io_service
。这允许每个线程io_service
,同时避免应用程序做出线程安全保证,因为所有完成处理程序都将通过单个服务发布,该服务的事件循环仅由单个线程处理。
boost::asio::io_service service1;
boost::asio::io_service service2;
// strand2 will be used by service2 to post handlers to service1.
boost::asio::strand strand2(service1);
boost::asio::io_service::work work2(service2);
socket.async_read_some(buffer, strand2.wrap(read_some_handler));
boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &service1));
service2.run();
threads.join_all();
这种方法确实会产生一些后果:
- 它需要由主程序运行的处理程序
io_service
被包裹通过strand::wrap() http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/io_service__strand/wrap.html.
- 异步链现在贯穿两个
io_service
s,增加了复杂性。重要的是要考虑到次要的情况io_service
不再有工作,导致其run()
回来。
异步链出现在同一个链中是很常见的。io_service
。因此,服务永远不会停止工作,因为完成处理程序会将额外的工作发布到io_service
.
| .------------------------------------------.
V V |
read_some_handler() |
{ |
socket.async_read_some(..., read_some_handler) --'
}
另一方面,当使用一条线将工作转移到另一条线时io_service
,包装的处理程序被调用service2
,使其将完成处理程序发布到service1
。如果包装处理程序是唯一的工作service2
, then service2
不再有工作,导致servce2.run()
回来。
service1 service2
====================================================
.----------------- wrapped(read_some_handler)
| .
V .
read_some_handler NO WORK
| .
| .
'----------------> wrapped(read_some_handler)
为了解决这个问题,示例代码使用了io_service::work http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/io_service__work.html for service2
以便run()
在明确告知之前一直处于封锁状态stop() http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/io_service/stop.html.