为什么Boost.Asio不支持基于事件的界面?

Dan*_*aum 7 c++ boost event-handling boost-asio

我试图了解Boost.Asio,意图使用条件变量和Boost.Asio来实现信号系统.

我已经看到其他StackOverflow问题提升asio异步等待条件变量,boost :: asio异步条件boost条件变量问题,但这些问题/答案都没有令人满意地触及我的一个基本问题:是真的吗那和/或是否存在一个根本原因,Boost.Asio不适用于条件变量,或者与条件变量自然吻合?

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

确实,与文件操作和套接字操作不同,在操作系统级别通常从不存在与信号条件相关联的回调函数(我认为 - 我不确定这一点).但是,在Boost.Asio中实现这样的回调处理程序似乎很简单,只需要用户提供一个回调函数,该函数在条件变量发出信号时被调用 - 正如用户必须为其他函数提供完成处理程序例程一样. 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
Run Code Online (Sandbox Code Playgroud)

也许,如果我试图填写代码片段上面提到的缺失细节,我会清楚地知道这不能以干净的方式工作.但是,这项工作并非易事.

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

附录

我已经将帖子的标题更改为引用"基于事件的界面",因为Tanner的答案在下面向我阐明了它实际上是一个基于事件的界面,我正在询问(不是真正的条件变量).

Tan*_*ury 18

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

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


如果需要进行基于事件的处理程序调用,那么一个相当简单的替代方法是使用Boost.Asio的超时服务器示例使用的相同方法: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();  
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*nck 4

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

  • 另一方面,条件变量也可以被认为是异步的,因为设置信号的线程不会阻塞,会立即继续执行,并且无法假设工作线程何时会并行执行工作。此外,条件变量的“同步”方面可以通过 Boost.Asio 转换为异步系统。即,当您将工作项放入 boost::asio::io_service 时,它​​会立即由​​工作线程(如果空闲)以与有信号条件触发的工作相同的方式处理。这是我在这里建议的语义。 (3认同)