使用多个io_service对象 [英] using multiple io_service objects
问题描述
我有我的应用程序,其中可以侦听和处理来自Internet套接字和Unix域套接字的消息.现在我需要将SSL添加到Internet套接字,我为应用程序中的所有套接字使用了一个io_service
对象.看来现在我需要为网络套接字和Unix域套接字添加单独的io_service
对象.我的应用程序中没有任何线程,我使用async_send
和async_recieve
和async_accept
来处理数据和连接.请给我指出使用多个带有异步处理程序的io_service
对象的任何示例.
I have my application in which listen and process messages from both internet sockets and unix domain sockets. Now I need to add SSL to the internet sockets, I was using a single io_service
object for all the sockets in the application. It seems now I need to add separate io_service
objects for network sockets and unix domain sockets. I don't have any threads in my application and I use async_send
and async_recieve
and async_accept
to process data and connections. Please point me to any examples using multiple io_service
objects with async handlers.
推荐答案
该问题具有一定程度的不确定性,好像需要多个io_service
对象一样.我在参考文档或该文档的概述中找不到任何内容 SSL 和
The question has a degree of uncertainty as if multiple io_service
objects are required. I could not locate anything in the reference documentation, or the overview for SSL and UNIX Domain Sockets that mandated separate io_service
objects. Regardless, here are a few options:
尝试使用单个io_service
.
如果没有对io_service
对象的直接句柄,但是对Boost.Asio I/O对象(例如套接字)具有句柄,则可以对关联的io_service
对象进行句柄处理通过调用 socket.get_io_service()
获得.
If you do not have a direct handle to the io_service
object, but you have a handle to a Boost.Asio I/O object, such as a socket, then a handle to the associated io_service
object can be obtained by calling socket.get_io_service()
.
如果需要多个io_service
对象,则将一个线程专用于每个io_service
. Boost.Asio的 HTTP Server 2 中使用了这种方法.例子.
If multiple io_service
objects are required, then dedicate a thread to each io_service
. This approach is used in Boost.Asio's HTTP Server 2 example.
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
和service2
都具有调用message_processor.process()
的完成处理程序,则message_processor.process()
必须是线程安全的或以线程安全的方式调用.
One consequence of this approach is that the it may require thread-safety guarantees to be made by the application. For example, if service1
and service2
both have completion handlers that invoke message_processor.process()
, then message_processor.process()
needs to either be thread-safe or called in a thread-safe manner.
io_service
为run()
.在 io_service::run()
会阻止到所有工作都已完成, io_service::poll()
将运行准备运行且不会阻塞的处理程序.这允许单个线程在多个io_service
对象上执行事件循环:
io_service
provides non-blocking alternatives to run()
. Where as io_service::run()
will block until all work has finished, io_service::poll()
will run handlers that are ready to run and will not block. This allows for a single thread to execute the event loop on multiple io_service
objects:
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));
}
}
为防止在没有现成的处理程序时出现繁忙循环,可能值得增加睡眠.请注意,这种睡眠可能会在事件的整体处理中引入延迟.
To prevent a tight-busy loop when there are no ready-to-run handlers, it may be worth adding in a sleep. Be aware that this sleep may introduce latency in the overall handling of events.
一种有趣的方法是使用 strand
将完成处理程序转移到单个io_service
.这样,每个io_service
都允许有一个线程,同时避免了使应用程序具有线程安全性保证的需要,因为所有完成处理程序都将通过单个服务发布,该服务的事件循环仅由单个线程处理.
One interesting approach is to use a strand
to transfer completion handlers to a single io_service
. This allows for a thread per io_service
, while preventing the need to have the application make thread-safety guarantees, as all completion handlers will post through a single service, whose event loop is only being processed by a single thread.
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();
这种方法确实会产生一些后果:
This approach does have some consequences:
- It requires handlers that are intended to by ran by the main
io_service
to be wrapped viastrand::wrap()
. - The asynchronous chain now runs through two
io_service
s, creating an additional level of complexity. It is important to account for the case where the secondaryio_service
no longer has work, causing itsrun()
to return.
异步链通常出现在同一io_service
中.因此,该服务永远不会耗尽工作,因为完成处理程序会将其他工作发布到io_service
.
It is common for an asynchronous chains to occur within the same io_service
. Thus, the service never runs out of work, as a completion handler will post additional work onto the io_service
.
| .------------------------------------------.
V V |
read_some_handler() |
{ |
socket.async_read_some(..., read_some_handler) --'
}
另一方面,当使用一条子线将工作转移到另一个io_service
时,在service2
中调用包装的处理程序,使它将完成处理程序发布到service1
中.如果包装的处理程序是service2
中唯一的工作,则service2
不再起作用,从而导致servce2.run()
返回.
On the other hand, when a strand is used to transfer work to another io_service
, the wrapped handler is invoked within service2
, causing it to post the completion handler into service1
. If the wrapped handler was the only work in service2
, then service2
no longer has work, causing servce2.run()
to return.
service1 service2
====================================================
.----------------- wrapped(read_some_handler)
| .
V .
read_some_handler NO WORK
| .
| .
'----------------> wrapped(read_some_handler)
为此,示例代码使用了 io_service::work
表示service2
,直到明确告知
To account for this, the example code uses an io_service::work
for service2
so that run()
remains blocked until explicitly told to stop()
.
这篇关于使用多个io_service对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!