Asio async_wait 给出操作取消

问题描述 投票:0回答:1

下面的简单 async_wait 示例给出了

Operation canceled
错误。

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

void waitForTimer(boost::asio::io_context& ioContext) {
    boost::asio::steady_timer timer(ioContext, boost::asio::chrono::seconds(1));

    timer.async_wait([&](const boost::system::error_code& error) {
        if (!error) {
            std::cout << "Timer expired! Asynchronous wait complete." << std::endl;
            waitForTimer(ioContext);  // Recursive call for infinite loop
        } else {
            std::cerr << "Error: " << error.message() << std::endl;
        }
    });
}

int main() {

    std::cout << "Using Boost "     
            << BOOST_VERSION / 100000     << "."  // major version
            << BOOST_VERSION / 100 % 1000 << "."  // minor version
            << BOOST_VERSION % 100                // patch level
            << std::endl;


    boost::asio::io_context ioContext;

    // Start the initial timer wait
    waitForTimer(ioContext);

    // Run the io_context to start asynchronous operations
    ioContext.run();    

    return 0;
}
Using Boost 1.82.0
Error: Operation canceled

我只想用无限循环运行那个简单的 async_wait 示例。但它不起作用。

c++ boost-asio asio
1个回答
2
投票

operation_canceled
是取消异步操作导致的。

销毁 IO 对象、调用

cancel
或在绑定的cancel_slot 上发出取消信号都可能取消异步操作。

此外,一些 IO 对象记录了隐式取消。例如。更改计时器对象的到期时间会隐式取消挂起的等待,例如

expiress_from_now

任何挂起的异步等待操作都将被取消。每个取消操作的处理程序将使用 boost::asio::error::operation_aborted 错误代码调用。

你的代码:问题

您的代码有一个局部变量

timer
。析构函数在函数返回之前运行,取消计时器。延长使用寿命,解决问题!

auto timer = make_shared<asio::steady_timer>(ioc, 1s);

timer->async_wait([timer, &ioc](boost::system::error_code const& error) {
    if (!error) {
        std::cout << "Timer expired! Asynchronous wait complete." << std::endl;
        waitForTimer(ioc); // Recursive call for infinite loop
    } else {
        std::cerr << "Error: " << error.message() << std::endl;
    }
});

看到它在Coliru上直播

虽然创建一个模拟您想要的循环定时器的类似乎更高效/优雅,但可以防止重复实例化和分配。

奖励:封装
IntervalTimer

使一切更易于使用和可重复使用。在这里,演示 2 个具有不同间隔(1.5 秒和 4 秒)的同步计时器:

住在Coliru

#include <boost/asio.hpp>
namespace asio = boost::asio;
using namespace std::chrono_literals;

struct IntervalTimer {
    using timer = asio::steady_timer;
    using duration = timer::duration;
    using callback = std::function<void()>;

    IntervalTimer(asio::any_io_executor ex, duration interval, callback cb)
        : ival_(interval)
        , timer_(ex, ival_)
        , cb_(std::move(cb))
    {
        start();
    }

  private:
    void start() {
        timer_.expires_from_now(ival_);
        timer_.async_wait([this](boost::system::error_code ec) {
            if (!ec) {
                if (cb_)
                    cb_();
                start();
            }
        });
    }

    duration ival_;
    timer    timer_;
    callback cb_;
};

#include <iostream>
#include <iomanip>
void trace(std::string_view msg) {
    static constexpr auto now   = std::chrono::steady_clock::now;
    static auto const     start = now();

    std::cout << std::fixed << std::setprecision(2) << msg << " at " << (now() - start) / 1.s << "s"
              << std::endl;
}

int main() {
    asio::io_context ioc;

    // Start the initial timer wait
    IntervalTimer timer1(ioc.get_executor(), 1500ms, []{ trace("timer 1 fired"); });
    IntervalTimer timer2(ioc.get_executor(), 4s,     []{ trace("timer 2 fired"); });

    // Run the io_context to start asynchronous operations
    ioc.run_for(10s);
}

打印

timer 1 fired at 1.50s
timer 1 fired at 3.00s
timer 2 fired at 4.00s
timer 1 fired at 4.50s
timer 1 fired at 6.00s
timer 1 fired at 7.50s
timer 2 fired at 8.00s
timer 1 fired at 9.00s

奖励 2:动态生命周期

为了使

IntervalTimer
也具有动态生命周期,您可以使用
enable_shared_from_this
Live On Coliru

struct IntervalTimer : std::enable_shared_from_this<IntervalTimer> {
    using timer = asio::steady_timer;
    using duration = timer::duration;
    using callback = std::function<void()>;

    IntervalTimer(asio::any_io_executor ex, duration interval, callback cb)
        : ival_(interval)
        , timer_(ex, ival_)
        , cb_(std::move(cb)) {}

    void start() {
        timer_.expires_from_now(ival_);
        timer_.async_wait([this, self = shared_from_this()](boost::system::error_code ec) {
            if (!ec) {
                if (cb_)
                    cb_();
                start();
            }
        });
    }

  private:
    duration ival_;
    timer    timer_;
    callback cb_;
};

具有相同的输出。

© www.soinside.com 2019 - 2024. All rights reserved.