Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What if a basic_waitable_timer is destructed when there are still async operations waiting on it?

What if a basic_waitable_timer is destructed when there are still async operations waiting on it? Is the behavior documented anywhere?

like image 231
updogliu Avatar asked Oct 16 '14 06:10

updogliu


2 Answers

When an IO object, such as basic_waitable_timer, is destroyed, its destructor will invoke destroy() on the IO object's service (not to be confused with the io_service), passing the IO object's implementation. A basic_waitable_timer's service is waitable_timer_service and fulfills the WaitableTimerService type requirement. The WaitableTimerService's requirement defines the post-condition for destroy() to cancel asynchronous wait operations, causing them to complete as soon as possible, and handler's for cancelled operations will be passed the error code boost::asio::error::operation_aborted.

service.destroy(impl); → Implicitly cancels asynchronous wait operations, as if by calling service.cancel(impl, e).

service.cancel(impl, e); → Causes any outstanding asynchronous wait operations to complete as soon as possible. Handlers for cancelled operations shall be passed the error code error::operation_aborted. Sets e to indicate success or failure.

Note that handlers for operations that have already been queued for invocation will not be cancelled and will have an error_code that reflects the success of the operation.


Here is a complete example demonstrating this behavior:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>

void demo_deferred_completion()
{
  std::cout << "[demo deferred completion]" << std::endl;
  boost::asio::io_service io_service;
  auto wait_completed = false;

  // Use scope to force lifetime.  
  {
    // Create the timer and initiate an async_wait operation that
    // is guaranteed to have expired.
    boost::asio::steady_timer timer(io_service);

    // Post a ready-to-run no-op completion handler into the io_service.
    // Although the order is unspecified, the current implementation
    // will use a predictable order.
    io_service.post([]{});

    // Initiate an async_wait operation that will immediately expire.
    timer.expires_at(boost::asio::steady_timer::clock_type::now());
    timer.async_wait(
        [&](const boost::system::error_code& error)
        {
          std::cout << "error: " << error.message() << std::endl;
          assert(error == boost::system::error_code()); // Success.
          wait_completed = true;          
        });

    // While this will only run one handler (the noop), it will
    // execute operations (async_wait), and if they are succesful
    // (time expired), the completion handler will be posted for
    // deferred completion.
    io_service.run_one();
    assert(!wait_completed); // Verify the wait handler was not invoked.
  } // Destroy the timer.

  // Run the handle_wait completion handler.
  io_service.run();
  assert(wait_completed);
}

void demo_cancelled()
{
  std::cout << "[demo cancelled]" << std::endl;
  boost::asio::io_service io_service;

  // Use scope to force lifetime.
  {
    boost::asio::steady_timer timer(io_service);

    // Initiate an async_wait operation that will immediately expire.
    timer.expires_at(boost::asio::steady_timer::clock_type::now());
    timer.async_wait(
        [](const boost::system::error_code& error)
        {
          std::cout << "error: " << error.message() << std::endl;
          assert(error ==
                 make_error_code(boost::asio::error::operation_aborted));
        });
  } // Destroy the timer.

  // Run the handle_wait completion handler.
  io_service.run();
}

int main()
{
  demo_deferred_completion();
  demo_cancelled();
}

Output:

[demo deferred completion]
error: Success
[demo cancelled]
error: Operation canceled
like image 171
Tanner Sansbury Avatar answered Nov 07 '22 05:11

Tanner Sansbury


It will be canceled: the completion handler is called with an error_code of operation_aborted

Relevant background information: boost::asio async handlers invoked without error after cancellation

like image 2
sehe Avatar answered Nov 07 '22 07:11

sehe