试图了解Boost.Asio的定制服务实现 [英] Trying to understand Boost.Asio custom service implementation

查看:145
本文介绍了试图了解Boost.Asio的定制服务实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想上,我们目前正在使用现有的专有的第三方网络协议的基础上编写自定义短耳服务。

I'm thinking about writing a custom Asio service on top of an existing proprietary 3rd party networking protocol that we are currently using.

根据短耳积分榜指南需要实现三个类来创建自定义短耳服务

According to Highscore Asio guide you need to implement three classes to create a custom Asio service:


  • 派生类的boost ::支持ASIO :: basic_io_object 重新presenting新的I / O对象。

  • 派生类的boost ::支持ASIO :: io_service对象::服务重新presenting与该I / O服务注册,并可以访问服务从I / O对象。

  • 不从其它类再presenting服务实现派生的类。

  • A class derived from boost::asio::basic_io_object representing the new I/O object.
  • A class derived from boost::asio::io_service::service representing a service that is registered with the I/O service and can be accessed from the I/O object.
  • A class not derived from any other class representing the service implementation.

网络协议的实现已经提供了异步操作,并具有(阻塞)事件循环。所以我想,我会把它变成我的服务实现类,并运行在一个内部工作线程的事件循环。到目前为止好。

The network protocol implementation already provides asynchronous operations and has a (blocking) event-loop. So I thought, I would put it into my service implementation class and run the event-loop in an internal worker thread. So far so good.

综观定制服务的一些例子,我注意到,服务类产卵自己的内螺纹(实际上他们实例化自己内部io_service对象实例)。例如:

Looking at some examples of custom services, I noticed that the service classes spawn their own internal threads (in fact they instantiate their own internal io_service instances). For example:


  1. 高分页面提供了一个目录监控例如。它本质上是围绕inotify的一个包装。有趣的类是的inotify / basic_dir_monitor_service.hpp 的inotify / dir_monitor_impl.hpp Dir_monitor_impl 处理与inofity实际的互动,这是阻塞,因此在后台线程中运行。我同意这一点。但 basic_dir_monitor_service 还有一个内部工作线程和所有似乎做的是洗牌的主要的之间的请求 io_service对象 dir_monitor_impl 。我玩与周围的code,除去 basic_dir_monitor_service ,而是直接发布请求主io_service对象,程序和以前一样仍然运行工作线程。

  1. The Highscore page provides a directory monitor example. It is essentially a wrapper around inotify. The interesting classes are inotify/basic_dir_monitor_service.hpp and inotify/dir_monitor_impl.hpp. Dir_monitor_impl handles the actual interaction with inofity, which is blocking, and therefore runs in a background thread. I agree with that. But the basic_dir_monitor_service also has an internal worker thread and all that seems to be doing is shuffling requests between main's io_service and the dir_monitor_impl. I played around with the code, removed the worker thread in basic_dir_monitor_service and instead posted requests directly to the main io_service and the program still ran as before.

在短耳的<一个href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/examples/cpp03_examples.html#boost_asio.examples.cpp03_examples.services\">custom记录器服务例如的,我已经注意到了同样的做法。在<一个href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp03/services/logger_service.hpp\"><$c$c>logger_service产卵内部工作线程来处理日志请求。我还没来得及与code打转转,但我认为,它应该是可以直接发布这些要求主要io_service对象也是如此。

In Asio's custom logger service example, I've noticed the same approach. The logger_service spawns an internal worker thread to handle the logging requests. I haven't had time to play around with that code, but I think, it should be possible to post these requests directly to the main io_service as well.

什么是有这些中介人员的优势在哪里?你不能发布所有的工作主io_service对象所有的时间?我错过了前摄器模式的某些重要方面?

What is the advantage of having these "intermediary workers"? Couldn't you post all work to the main io_service all the time? Did I miss some crucial aspect of the Proactor pattern?

我也许应该提及我一个动力不足的单核心的嵌入式系统编写软件。已具备了这些额外的线程似乎只是造成不必要的上下文切换,我想尽量避免它。

I should probably mention that I'm writing software for an underpowered single-core embedded system. Having these additional threads in place just seems to impose unnecessary context switches which I'd like to avoid if possible.

推荐答案

在短,一致性。该服务试图满足用户期望通过提供Boost.Asio的该服务提出

In short, consistency. The services attempt to meet user expectations set forth by the services Boost.Asio provides.

使用内部 io_service对象提供的所有权和处理程序的控制权明确分开。如果自定义服务岗位内部处理程序到用户的 io_service对象,那么服务的内部处理程序的执行变得含蓄再加上用户的处理程序。想想,这将如何影响与<用户的期望href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/examples/cpp03_examples.html#boost_asio.examples.cpp03_examples.services\">Boost.Asio记录器服务例如:

Using an internal io_service provides a clear separation of ownership and control of handlers. If a custom service posts its internal handlers into the user's io_service, then execution of the service's internal handlers becomes implicitly coupled with the user's handlers. Consider how this would impact user expectations with the Boost.Asio Logger Service example:


  • logger_service 写入一个处理程序中的文件流。因此,一个程序,从来没有处理 io_service对象事件循环,比如一个仅使用同步API,就不会写入日志消息。

  • logger_service 将不再是线程安全的,潜在的调用未定义的行为,如果 io_service对象是由多个处理线程。

  • logger_service 的内部运作的寿命是由的 io_service对象限制。例如,当调用服务的 shutdown_service()函数,其所属的 io_service对象已经结束了一生。因此,消息无法通过 logger_service记录::日志() shutdown_service(),因为它会试图发布一个内部处理程序到 io_service对象,其寿命已经结束。

  • 的用户可能不再假定的动作和处理程序之间的一对一的映射。例如:

  • The logger_service writes to the file stream within a handler. Thus, a program that never processes the io_service event loop, such as one that only uses the synchronous API, would never have log messages written.
  • The logger_service would no longer be thread-safe, potentially invoking undefined behavior if the io_service is processed by multiple threads.
  • The lifetime of the logger_service's internal operations is constrained by that of the io_service. For example, when a service's shutdown_service() function is invoked, the lifetime of the owning io_service has already ended. Hence, messages could not be logged via logger_service::log() within shutdown_service(), as it would attempt to post an internal handler into the io_service whose lifetime has already ended.
  • The user may no longer assume a one-to-one mapping between an operation and handler. For example:

boost::asio::io_service io_service;
debug_stream_socket socket(io_service);
boost::asio::async_connect(socket, ..., &connect_handler);
io_service.poll();
// Can no longer assume connect_handler has been invoked.

在这种情况下, io_service.poll()可以调用处理程序内部的 logger_service ,而不是 connect_handler()

In this case, io_service.poll() may invoke the handler internal to the logger_service, rather than connect_handler().

此外,这些内螺纹试图模拟由Boost.Asio的<一个内部使用的行为href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/overview/core/threads.html#boost_asio.overview.core.threads.internal_threads\">itself:

Furthermore, these internal threads attempt to mimic the behavior used internally by Boost.Asio itself:

该库的特定平台实现可以使用一个或多个内螺纹的仿效不同步。尽可能的,这些线程必须是不可见的图书馆用户。

The implementation of this library for a particular platform may make use of one or more internal threads to emulate asynchronicity. As far as possible, these threads must be invisible to the library user.

在目录监控例如,内部线程是用prevent无限期封锁用户的 io_service对象等待一个事件。一旦发生事件时,完成处理程序已经准备好被调用,因此内螺纹发布用户处理程序到用户的 io_service对象延期调用。此实现模拟异步性具有内螺纹即大多对用户不可见。


Directory Monitor example

In the directory monitor example, an internal thread is used to prevent indefinitely blocking the user's io_service while waiting for an event. Once an event has occurred, the completion handler is ready to be invoked, so the internal thread post the user handler into the user's io_service for deferred invocation. This implementation emulates asynchronicity with an internal thread that is mostly invisible to the user.

有关详细信息,在异步监视操作是通过 dir_monitor发起:: async_monitor(),一个 basic_dir_monitor_service :: monitor_operation 发布到内部 io_service对象。当被调用时,该操作将调用 dir_monitor_impl :: popfront_event(),一个潜在的阻塞调用。因此,如果 monitor_operation 发布到用户的 io_service对象,用户的线程可能被无限期封锁。请考虑以下code中的影响:

For details, when an asynchronous monitor operation is initiated via dir_monitor::async_monitor(), a basic_dir_monitor_service::monitor_operation is posted into the internal io_service. When invoked, this operation invokes dir_monitor_impl::popfront_event(), a potentially blocking call. Hence, if the monitor_operation is posted into the user's io_service, the user's thread could be indefinitely blocked. Consider the affect on the following code:

boost::asio::io_service io_service;
boost::asio::dir_monitor dir_monitor(io_service); 
dir_monitor.add_directory(dir_name); 
// Post monitor_operation into io_service.
dir_monitor.async_monitor(...);
io_service.post(&user_handler);
io_service.run();

在上面的code,如果 io_service.run()调用 monitor_operation ,然后再 user_handler()将不会被调用,直到 dir_monitor 注意到在 DIR_NAME 目录。因此, dir_monitor 服务的实现不会以一致的方式行事,大多数用户来自其他服务的期望。

In the above code, if io_service.run() invokes monitor_operation first, then user_handler() will not be invoked until dir_monitor observes an event on the dir_name directory. Therefore, dir_monitor service's implementation would not behave in a consistent manner that most users expect from other services.

使用内螺纹和 io_service对象


  • 减轻登录用户的螺纹(s)的执行有可能阻断或内螺纹内昂贵的呼叫上的开销。

  • 担保的std ::的ofstream 的线程安全,因为只有单一的内螺纹写入流。如果日志记录在 logger_service直接完成::日志()或者 logger_service 公布了其处理程序到用户的 io_service对象,则显式同步将需要线程安全。其他的同步机制可能会引入更多的开销和复杂性进入实施。

  • 允许<一个href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/Service.html\"><$c$c>services登录在<一个消息href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_service__service/shutdown_service.html\"><$c$c>shutdown_service().在<一个href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_service/_io_service.html\">destruction,在 io_service对象将:

  • Mitigates the overhead of logging on the user's thread(s) by performing potentially blocking or expensive calls within the internal thread.
  • Guarantees the thread-safety of std::ofstream, as only the single internal thread writes to the stream. If logging was done directly within logger_service::log() or if logger_service posted its handlers into the user's io_service, then explicit synchronization would be required for thread-safety. Other synchronization mechanisms may introduce greater overhead or complexity into the implementation.
  • Allows for services to log messages within shutdown_service(). During destruction, the io_service will:


  1. 关闭它的每项服务。

  2. 破坏定于递延调用,所有未调用处理程序的 io_service对象或任何与其相关的秒。

  3. 摧毁它的每项服务。

  1. Shutdown each of its services.
  2. Destroy all uninvoked handlers that were scheduled for deferred invocation in the io_service or any of its associated strands.
  3. Destroy each of its services.


作为终身用户的 io_service对象已经结束,其事件队列既不是正在处理,也可以附加处理程序发布。由自己的内部 io_service对象由自己的线程处理, logger_service 使得其他服务时记录消息的 shutdown_service()


As the lifetime of the user's io_service has ended, its event queue is neither being processed nor can additional handlers be posted. By having its own internal io_service that is processed by its own thread, logger_service enables other services to log messages during their shutdown_service().

在实现自定义的服务,在这里是需要考虑的几点:

When implementing a custom service, here are a few points to consider:


  • 块上的内螺纹的所有信号。

  • 从不调用用户的code直接。

  • 如何跟踪和后期用户处理程序时,实现被销毁。

  • 由被服务的实现之间共享服务资源拥有(S)。

在过去的两分, dir_monitor I / O对象表现出行为的用户可能没有想到。由于服务中的单个线程调用了一个实现的事件队列阻塞操作,这有效地阻止该操作可能立即完成了各自的实现:

For the last two points, the dir_monitor I/O object exhibits behavior that users may not expect. As the single thread within the service invokes a blocking operation on a single implementation's event queue, it effectively blocks operations that could potentially complete immediately for their respective implementation:

boost::asio::io_service io_service;
boost::asio::dir_monitor dir_monitor1(io_service); 
dir_monitor1.add_directory(dir_name1); 
dir_monitor1.async_monitor(&handler_A);

boost::asio::dir_monitor dir_monitor2(io_service); 
dir_monitor2.add_directory(dir_name2); 
dir_monitor2.async_monitor(&handler_B);
// ... Add file to dir_name2.

{
  // Use scope to enforce lifetime.
  boost::asio::dir_monitor dir_monitor3(io_service); 
  dir_monitor3.add_directory(dir_name3); 
  dir_monitor3.async_monitor(&handler_C);
}
io_service.run();

虽然有相关的操作 handler_B()(成功)和 handler_C()(中止)不会阻碍在单线程 basic_dir_monitor_service 被阻塞,等待更改 dir_name1

Although the operations associated with handler_B() (success) and handler_C() (aborted) would not block, the single thread in basic_dir_monitor_service is blocked waiting for a change to dir_name1.

这篇关于试图了解Boost.Asio的定制服务实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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