使用多个io_service对象 [英] using multiple io_service objects

查看:115
本文介绍了使用多个io_service对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我的应用程序,其中可以侦听和处理来自Internet套接字和Unix域套接字的消息.现在我需要将SSL添加到Internet套接字,我为应用程序中的所有套接字使用了一个io_service对象.看来现在我需要为网络套接字和Unix域套接字添加单独的io_service对象.我的应用程序中没有任何线程,我使用async_sendasync_recieveasync_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();

此方法的一个后果是,它可能要求应用程序提供线程安全保证.例如,如果service1service2都具有调用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:

  • 它要求要由主io_service运行的处理程序通过
  • It requires handlers that are intended to by ran by the main io_service to be wrapped via strand::wrap().
  • The asynchronous chain now runs through two io_services, creating an additional level of complexity. It is important to account for the case where the secondary io_service no longer has work, causing its run() 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆