为什么Boost.Asio不支持基于事件的接口

Why does Boost.Asio not support an event-based interface?

本文关键字:事件 接口 于事件 Boost Asio 不支持 为什么      更新时间:2023-10-16

我正在尝试理解Boost。Asio,意图潜在地实现一个使用条件变量与Boost.Asio相结合的信号系统。

我已经看到了其他StackOverflow问题boost::asio异步等待条件变量,boost::asio异步条件和boost条件变量问题,但这些问题/答案都没有令人满意地触及我的一个基本问题:是真的吗,和/或有一个根本的原因,boost。Asio不适用于条件变量,还是与条件变量自然匹配?

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

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

例如(这只是一个快速的想法,不是一个完整的原型-它没有包含足够的参数来处理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?

附录

我已经改变了文章的标题,以参考"基于事件的接口",因为Tanner的回答,下面,已经向我澄清,这是一个真正的基于事件的接口,我问(不是真正的条件变量)

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

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


如果需要发生基于事件的处理程序调用,那么一个相当简单的替代方法是使用相同的方法Boost。Asio的超时服务器示例使用:boost::asio::deadline_timerdeadline_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();  
}

条件变量是一个同步概念:它们阻塞一个线程,直到另一个线程发生某些事情。提振。Asio是一个异步框架:它以非阻塞的方式提供事件的多路复用。这两个人似乎不太般配。如果您想要异步事件通知,请查看Linux上的eventfd,它应该可以与Boost.Asio一起使用。