为什么Boost.Asio不支持基于事件的界面? [英] Why does Boost.Asio not support an event-based interface?

查看:296
本文介绍了为什么Boost.Asio不支持基于事件的界面?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解Boost.Asio,目的是潜在地实施使用条件变量的Boost.Asio的信号系统。



我已经看到其他StackOverflow问题提升asio异步等待条件变量 boost :: asio异步条件提升条件变量问题,但是这些问题/答案中没有一个令人满意地触及了我所关心的一个重要问题:是否真的,和/或是否有一个根本原因,Boost.Asio不适用于或与条件变量自然契合?



我的想法是条件变量是使用操作内部实现ng系统级同步对象(例如,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服务;
boost :: mutex mut;
boost :: condition_variable cond;

//以下类是**由我组成** - 这样的一个类是一个好主意吗?
boost :: asio :: io_service :: condition_service
condserv(service,cond,mut,condition_handler_function);

condserv.async_wait_on_signal();

service.run(); //当通过notify_one()表示条件变量时,
//'handler_function()'将被称为


// ...在某些其他线程中,稍后:
cond.notify_one(); //这将在这个理论代码中触发'handler_function()'
//

也许如果我试图填写上面代码段中提到的缺失的细节,那我们就可以清楚地看到,这样做无法以干净的方式工作。但是,这种努力是不平凡的。



因此,我想在此发布问题。有没有一个很好的理由为什么条件变量不支持Boost.Asio?



ADDENDUM



我已经将帖子的标题改为引用基于事件的界面,因为下面的Tanner的答案已经向我澄清说,这真的是一个基于事件的界面,我正在询问(不是真的条件变量)

解决方案

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



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






如果事件需要发生处理程序调用,那么一个相当简单的替代方法就是使用相同的方法Boost.Asio的超时服务器示例使用: 提高:: ASIO :: deadline_timer 。可以将 deadline_timer 的到期时间设置为 posix_time :: pos_infin ,导致 async_wait 的处理程序一旦计时器被取消,只能被调用:




  • cancel() 可以作为 notify_all(),其中所有未处理的处理程序都排队等待调用。

  • cancel_one() 可以作为 notify_one ),其中最多一个未处理的处理程序排队等待调用。



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

  #include& LT;&的iostream GT; 

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

类事件
{
public:
显式
事件(boost :: asio :: io_service& io_service)
:timer_(io_service )
{
//将到期设置为无穷大将导致处理程序
//等待定时器,直到取消。
timer_.expires_at(boost :: posix_time :: pos_infin);
}

模板< typename WaitHandler>
void async_wait(WaitHandler handler)
{
// bind用于使用户提供的处理程序适应截止日期
//定时器的等待处理程序类型要求。
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;
事件事件(io_service);

//将工作添加到服务中。
event.async_wait(& on_event);

//运行io_service。
boost :: thread thread(boost :: bind(& boost :: asio :: io_service :: run,
& io_service));

//触发事件,导致on_event处理程序运行。
event.notify_one();

thread.join();
}


I am attempting to understand Boost.Asio, with the intention of potentially implementing a signaling system using condition variables in conjunction with Boost.Asio.

I have seen the other StackOverflow questions boost asio asynchronously waiting on a condition variable, boost::asio async condition, and boost condition variable issue, but none of these questions/answers have satisfactorily touched on an essential question that I have: Is it true that, and/or is there a fundamental reason why, Boost.Asio is not applicable to, or a natural fit with, condition variables?

My thinking is that condition variables are internally implemented using operating-system level synchronization objects (for example, boost::thread::condition_variable on Windows uses a Windows OS semaphore). Because, to my current understanding, boost::asio::io_service is intended to encapsulate OS-level synchronization objects, condition variables would therefore seem to be a natural fit.

It is true that unlike file operations and socket operations, there is typically never a callback function at the operating system level associated with a signaled condition (I think - I am not sure about this). However, it would seem simple enough to implement such a callback handler within Boost.Asio by simply requiring the user to provide a callback function that is to be called when a condition variable is signaled - just as users must provide a completion handler routine for other boost::asio::io_service services.

For example (this is just a quick thought, not a complete prototype - it does not include sufficient parameters to deal with notify_one() vs. notify_all(), doesn't indicate how the service knows when to exit, and likely has other glaring omissions or flaws):

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

Perhaps, if I tried to fill in the missing details noted above the code snippet, it would become clear to me that this could not work in a clean way. However, this effort is non-trivial.

Therefore, I would like to post the question here. Is there a good reason why condition variables are not supported by Boost.Asio?

ADDENDUM

I have changed the title of the post to reference "Event-based interface", since Tanner's answer, below, has clarified to me that it is really an Event-based interface that I am asking about (not really condition variables).

解决方案

Boost.Asio is a C++ library for network and low-level I/O programming. As such, OS-level synchronization objects, such as condition variables, are outside of the scope of the library, and a much better fit for Boost.Thread. The Boost.Asio author often presents the boost::asio::io_service as the bridge or link between the application and the OS. While this may be an over simplification, it is within the context of the OS's I/O services.

Asynchronous programming already has an innate complexity due to the separation in time and space between operation initiation and completion. Strands provided a fairly clean solution to provide strict sequential invocation of handlers, without the need of explicit locking. As the locking is both implicit and thread-safe, application code can use strands without the fear of deadlocking. On the other hand, having boost::asio::io_service::condition_service perform implicit synchronization on an externally provided object may turn a complex library into a complicated one. It may not be clear to the application developer what mutex on which the handler was synchronized, and the state of the mutex. Additionally, it introduces the ability for applications to more easily deadlock the event processing loop due to the implicit locking.


If event-based handler invocation needs to occur, then one fairly simple alternative is use the same approach Boost.Asio's timeout server example uses: boost::asio::deadline_timer. A deadline_timer's expiry time can be set to posix_time::pos_infin, causing an async_wait's handler to only be invoked once the timer has been canceled:

  • cancel() could function as notify_all(), where all outstanding handlers are queued for invocation.
  • cancel_one() could function as notify_one(), where a max of one outstanding handler is queued for invocation.

A simple example, ignoring error code handling, is as follows:

#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();  
}

这篇关于为什么Boost.Asio不支持基于事件的界面?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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