c++ - 为什么 Boost.Asio 不支持基于事件的接口(interface)?

标签 c++ boost event-handling boost-asio

我试图理解 Boost.Asio,目的是潜在地使用条件变量结合 Boost.Asio 来实现信号系统。

我看过其他 StackOverflow 问题 boost asio asynchronously waiting on a condition variable , boost::asio async condition , 和 boost condition variable issue ,但这些问题/答案都没有令人满意地触及我的一个基本问题:Is it true that and/or is there a fundamental reason why, Boost.Asio is not applicable to, or a natural fit with , 条件变量?

我的想法是,条件变量是使用操作系统级同步对象在内部实现的(例如,Windows 上的 boost::thread::condition_variable 使用 Windows 操作系统信号量)。因为,根据我目前的理解,boost::asio::io_service 旨在封装 OS 级同步对象,因此条件变量似乎很适合。

的确,与文件操作和套接字操作不同,在操作系统级别通常没有与信号条件相关联的回调函数(我认为 - 我我不确定)。然而,在 Boost.Asio 中实现这样的回调处理程序似乎很简单,只需要求用户提供一个回调函数,该回调函数将在条件变量发出信号时调用——就像用户必须为其他人提供完成处理程序例程一样boost::asio::io_service 服务。

例如(这只是一个快速的想法,不是一个完整的原型(prototype)——它没有包含足够的参数来处理 notify_one() 和 notify_all(),没有说明服务如何知道何时退出,并且可能有其他明显的遗漏或缺陷):

void condition_handler_function() {}
boost::asio::io_service service;
boost::mutex mut;
boost::condition_variable cond;

// The following class is **made up by me** - would such a class be a good idea?
boost::asio::io_service::condition_service
             condserv(service, cond, mut, condition_handler_function); 

condserv.async_wait_on_signal();

service.run(); // when condition variable is signaled by notify_one(),
               // 'handler_function()' would be called


// ... in some other thread, later:
cond.notify_one(); // This would trigger 'handler_function()'
                   // in this theoretical code

也许,如果我尝试填写代码片段上方提到的缺失细节,我就会清楚这无法以干净的方式工作。然而,这种努力并非微不足道。

因此,我想在这里发布问题。 Boost.Asio 不支持条件变量是否有充分的理由?

附录

我已经更改了帖子的标题以引用“基于事件的接口(interface)”,因为 Tanner 在下面的回答向我澄清了我所询问的实际上是一个基于事件的接口(interface)(不是真正的条件变量) .

最佳答案

Boost.Asio 是一个用于网络和低级 I/O 编程的 C++ 库。因此,操作系统级别的同步对象(例如条件变量)不在库的范围内,更适合 Boost.Thread。 Boost.Asio 作者经常将 boost::asio::io_service 作为应用程序和操作系统之间的桥梁或链接。虽然这可能过于简化,但它在操作系统的 I/O 服务的上下文中。

由于操作启动和完成之间的时间和空间分离,异步编程已经具有先天的复杂性。 Strands提供了一个相当干净的解决方案来提供处理程序的严格顺序调用,而不需要显式锁定。由于锁定是隐式的和线程安全的,应用程序代码可以使用链而不用担心死锁。另一方面,让 boost::asio::io_service::condition_service 对外部提供的对象执行隐式同步可能会将一个复杂的库变成一个复杂的库。应用程序开发人员可能不清楚同步处理程序的互斥锁以及互斥锁的状态。此外,由于隐式锁定,它还引入了应用程序更容易死锁事件处理循环的能力。


如果需要调用基于事件的处理程序,那么一种相当简单的替代方法是使用相同的方法 Boost.Asio 的 timeout server示例使用:boost::asio::deadline_timer . deadline_timer 的到期时间可以设置为 posix_time::pos_infin,导致 async_wait的处理程序仅在定时器被取消后被调用:

  • cancel()可以用作 notify_all(),其中所有未完成的处理程序都排队等待调用。
  • cancel_one()可以用作 notify_one(),其中最多有一个未完成的处理程序排队等待调用。

一个简单的例子,忽略错误码处理,如下:

#include <iostream>

#include <boost/asio.hpp>
#include <boost/thread.hpp>

class event
{
public:
  explicit
  event(boost::asio::io_service& io_service) 
    : timer_(io_service)
  {
    // Setting expiration to infinity will cause handlers to
    // wait on the timer until cancelled.
    timer_.expires_at(boost::posix_time::pos_infin);
  }

  template <typename WaitHandler>
  void async_wait(WaitHandler handler)
  {
    // bind is used to adapt the user provided handler to the deadline 
    // timer's wait handler type requirement.
    timer_.async_wait(boost::bind(handler));
  }

  void notify_one() { timer_.cancel_one(); }
  void notify_all() { timer_.cancel();     }

private:
  boost::asio::deadline_timer timer_;
};

void on_event() { std::cout << "on_event" << std::endl; }

int main()
{
  boost::asio::io_service io_service;
  event event(io_service);

  // Add work to service.
  event.async_wait(&on_event);

  // Run io_service.
  boost::thread thread(boost::bind(&boost::asio::io_service::run,
                       &io_service));

  // Trigger event, causing the on_event handler to run.
  event.notify_one();

  thread.join();  
}

关于c++ - 为什么 Boost.Asio 不支持基于事件的接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17005258/

相关文章:

c++ - clang 3.8 make 文件失败

c++ - 创建基于模板和 boost::shared_ptr 的通用工厂时出现编译错误

c++ - 将 numpy 数组与 boost.python : pyublas or boost. numpy 交换?

java - 订阅按钮点击而不内联实现

c++ - 当终止条件取决于来自不同部分的更新时,为什么 OMP 并行部分中的 while 循环无法终止

c++ - 在 C++ 中打印集合 vector

C++程序不会进入for循环

c++ - 如何实现is_STL_vector

python - 使用 Kivy 为同一事件添加多个处理程序的最佳/正确方法是什么?

c# - Javascript 执行 .cs 中的代码?