可一个boost :: ASIO :: yield_context被用作做取消当deadline_timer处理? [英] Can a boost::asio::yield_context be used as a deadline_timer handler when doing cancel?

查看:470
本文介绍了可一个boost :: ASIO :: yield_context被用作做取消当deadline_timer处理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够做到在特定事件的异步等待。还有很多类似的问题和答案就在这里(和所有编译并为我的工作),但没有与我的具体情况。基本上,我需要能够做的是一个async_wait,传递一个背景下收益率作为处理,到无限期等待一个计时器,然后由另一个线程取消。

I'd like to be able to do an asynchronous wait on a specific event. There are a lot of similar questions and answers on here (and all compile and work for me) but none with my specific scenario. Basically, what I need to be able to do is an async_wait, passing a yield context as the handler, to a timer that waits indefinitely, and is then canceled by another thread.

例如,有<一个href=\"http://stackoverflow.com/questions/17005258/why-does-boost-asio-not-support-an-event-based-interface-for-example-something#\"标题=这个问题>这个问题这确实很相似,但不是利用产量方面的东西,它使用一个单独的,独立的处理程序。也有像<一个href=\"http://stackoverflow.com/questions/21771639/can-i-use-a-stackful-coroutine-as-the-wait-handler-of-a-steady-timer-which-is-de\"标题=这个问题>这个问题的,它使用的产率方面,而是等待指定的时间量

For example, there is this question which does something very similar, but instead of using a yield context, it uses a separate, standalone handler. There is also something like this question which uses a yield context, but waits for a specified amount of time.

我可以改变我的code看起来像上述任一,事情做工精细的两个例子。但是,当我结合了yield_context处理程序和取消计时器有人原因,我得到以下异常:

I can change my code to look like either of the two examples above and things work fine. But for someone reason when I combine a yield_context handler and a cancelled timer, I get the following exception:

libc++abi.dylib: terminating with uncaught exception of type boost::exception_detail::clone_impl<boost::exception_detail::current_exception_std_exception_wrapper<std::runtime_error> >: 
Program ended with exit code: 9

据我所知,它看起来像的东西呛试图调用完成处理程序(在这种情况下是屈服上下文)时。

From what I can tell, it looks like things choke when trying to invoke the completion handler (which in this case is the yield context).

好吧,够咿呀学语,这里的code。我试图想出简单的例子尽可能的来说明吧:

Alright, enough babbling, here's the code. I've tried to come up with as simple of an example as possible to illustrate it:

类:

class Foo {
public:
  Foo() : work_(io_service_), timer_(io_service_) {
    thread_pool_.create_thread(boost::bind(&boost::asio::io_service::run, &io_service_));
    timer_.expires_from_now(boost::posix_time::pos_infin);
  }
  ~Foo() {
    io_service_.stop();
    thread_pool_.join_all();
  }

  void Wait(const boost::asio::yield_context& context) {
    std::cout << "Waiting" << std::endl;
    timer_.async_wait(context);
    std::cout << "Done waiting" << std::endl;
  }

  void Notify() {
    std::cout << "Notifying" << std::endl;
    timer_.cancel();
  }

  void Write(int num) {
    std::cout << "Sending buffer event" << std::endl;
    Notify();
    std::cout << "Sent buffer event" << std::endl;
  }

  void Read(const boost::asio::yield_context& context) {
    std::cout << "Waiting on buffer event, size is " << buffer_.size() << std::endl;
    Wait(context);
    std::cout << "Received buffer event, size is now " << buffer_.size() << std::endl;
  }

  std::vector<int> buffer_;
  boost::asio::io_service io_service_;
  boost::thread_group thread_pool_;
  boost::asio::io_service::work work_;
  boost::asio::deadline_timer timer_;
};

主营:

boost::shared_ptr<Foo> foo(new Foo());    
boost::asio::spawn(foo->io_service_, boost::bind(&Foo::Read, foo, _1));
boost::this_thread::sleep(boost::posix_time::seconds(2));
foo->Write(1);
boost::this_thread::sleep(boost::posix_time::seconds(4));

输出:

Waiting on buffer event
Waiting
Sending buffer event
Notifying
Sent buffer event
libc++abi.dylib: terminating with uncaught exception of type boost::exception_detail::clone_impl<boost::exception_detail::current_exception_std_exception_wrapper<std::runtime_error> >: 

现在,如果我更改等待方法将时间将超时之前取消被调用,一切都很好。即:

Now, if I change the wait method to a time that will time out before the cancel is called, everything is fine. I.e.:

void Wait(const boost::asio::yield_context& context) {
    std::cout << "Waiting" << std::endl;
    timer_.expires_from_now(boost::posix_time::seconds(1));
    timer_.async_wait(context);
    std::cout << "Done waiting" << std::endl;
  }

或者,如果我改变迫不及待地用一个单独的处理方法,一切都很好。即:

Or, if I change wait to use a separate handler method, everything is fine. I.e.:

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

void Wait(const boost::asio::yield_context& context) {       
  std::cout << "Waiting" << std::endl;
  timer_.async_wait(boost::bind(&Foo::Handler, this));
  std::cout << "Done waiting" << std::endl;
}

我猜想一定有更简单的东西,我在这里失踪:要么这是不可能因为某些原因或我在做一些愚蠢的错误。不管怎样,先谢谢了。

I'm assuming there must be something simpler I'm missing here: either this is impossible for some reason or I'm making some dumb mistake. Anyway, thanks in advance.

推荐答案

()操作正在 async_wait <一个href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/basic_deadline_timer/cancel/overload1.html\"相对=nofollow>取消,导致异步操作与的boost ::支持ASIO ::错误:: operation_aborted 失败。正如 Stackful协同程序文件,当的boost ::支持ASIO :: yield_context 检测到异步操作失败,在转换的boost ::系统::错误_ $ C $ç SYSTEM_ERROR 异常并抛出。在协程,既考虑:

The async_wait() operation is being cancelled, resulting in the asynchronous operation failing with an error code of boost::asio::error::operation_aborted. As noted in the Stackful Coroutines documentation, when the boost::asio::yield_context detects that the asynchronous operation has failed, it converts the boost::system::error_code into a system_error exception and throws. Within the coroutine, consider either:

  • Initiating the asynchronous operation with a handler of context[error_code], causing the yield_context to populate the provided boost::system::error_code on failure rather than throwing.

boost::system::error_code error;
timer_.async_wait(context[error]); // On failure, populate error.


  • SYSTEM_ERROR 和SUP preSS它。

  • Catch the system_error and suppress it.

    在故障Boost.Asio的将填充的boost ::系统::错误_ code 如果应用程序能够接收它,否则会抛出异常。可以在整个Boost.Asio的可以观察到这种模式:

    On failure Boost.Asio will populate a boost::system::error_code if the application is capable of receiving it, otherwise it will throw an exception. This pattern can be observed throughout Boost.Asio:


    • 所有<一个href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/asynchronous_operations.html\"相对=nofollow>异步操作处理程序的接受左值常量的boost ::系统::错误_ code 作为他们的第一个参数。因此,发起函数应该不丢,作为应用程序将在处理程序中的错误的通知。使用仿函数时丢弃额外的参数,如这并不总是显而易见的的boost ::绑定

    • 同步操作超载支持投掷和非抛出的版本。例如,<一href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/basic_deadline_timer/cancel/overload1.html\"相对=nofollow> timer.cancel() 将抛出失败,其中作为<一个href=\"http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/basic_deadline_timer/cancel/overload2.html\"相对=nofollow> timer.cancel(的boost ::系统::错误_ code&安培;) 将设置错误_ code 来指示错误。

    • 如上所述,当异步操作一个stackful协程中失败,且 yield_context 处理程序不提供的boost ::系统::错误_ code ,那么 SYSTEM_ERROR 会抛出异常。

    • 当使用期货,如果异步操作失败,那么错误_ code 转换成 SYSTEM_ERROR 异常,并传回通过未来
    • 呼叫者
    • All asynchronous operation handler's accept an lvalue const boost::system::error_code as their first parameter. Hence, the initiating function should not throw, as the application will be informed of the error within the handler. This is not always apparent when using functors that discards extra arguments, such as boost::bind.
    • Synchronous operations are overloaded to support throwing and non-throwing versions. For example, timer.cancel() will throw on failure, where as timer.cancel(boost::system::error_code&) will set the error_code to indicate the error.
    • As noted above, when an asynchronous operation fails within a stackful coroutine and the yield_context handler is not provided a boost::system::error_code, then a system_error exception will be thrown.
    • When using futures, if the asynchronous operation fails, then the error_code is converted into a system_error exception and passed back to the caller through the future.

    下面是基于运行完成最初的问题一个完整的小例子。

    Here is a complete minimal example based on the original problem that runs to completion.

    #include <boost/asio.hpp>
    #include <boost/asio/spawn.hpp>
    
    int main()
    {
      boost::asio::io_service io_service;
      boost::asio::deadline_timer timer(io_service);
      timer.expires_from_now(boost::posix_time::pos_infin);
    
      boost::asio::spawn(io_service,
        [&](boost::asio::yield_context yield)
        {
          // As only one thread is processing the io_service, the posted
          // timer cancel will only be invoked once the coroutine yields.
          io_service.post([&](){ timer.cancel(); });
    
          // Initiate an asynchronous operation, suspending the current coroutine,
          // and allowing the io_service to process other work (i.e. cancel the 
          // timer).  When the timer is cancelled, the asynchronous operation is
          // completed with an error,  causing the coroutine to resume.  As an
          // error_code is provided, the operation will not throw on failure.
          boost::system::error_code error;
          timer.async_wait(yield[error]);
          assert(error == boost::asio::error::operation_aborted);
        });
    
      io_service.run();
    }
    

    这篇关于可一个boost :: ASIO :: yield_context被用作做取消当deadline_timer处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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