【问题标题】:Wait for timer in other coroutine (Asio)等待其他协程中的计时器(Asio)
【发布时间】:2021-06-28 18:40:17
【问题描述】:

使用asio::spawn时,是否可以在单独的协程中等待计时器?例如,在下面的代码中,我希望 coroutine 2 started 打印到控制台,然后在 5 秒后,coroutine 2 finished

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

int main() {

  boost::asio::io_context io;

  // coroutine 1
  boost::asio::spawn(io, [&](boost::asio::yield_context yield) {
    boost::asio::deadline_timer timer(io, boost::posix_time::seconds(5));
    timer.async_wait(yield);
  });

  // coroutine 2
  boost::asio::spawn(io, [&](boost::asio::yield_context yield) {
    std::cout << "coroutine 2 started" << std::endl;
    // wait for coroutine 1 timer to finish
    std::cout << "coroutine 2 finished" << std::endl;
  });

  io.run();
}

【问题讨论】:

    标签: c++ c++11 boost boost-asio coroutine


    【解决方案1】:

    有很多方法,大多数都集中在共享计时器上。

    我能想到的最简单的方法是从 coro1 产生 coro2 (“分叉”,如果你愿意的话),因为为什么不呢:

    Live On Wandbox

    #include <boost/asio.hpp>
    #include <boost/asio/spawn.hpp>
    #include <iostream>
    
    using namespace std::chrono_literals;
    using boost::asio::yield_context;
    using timer = boost::asio::steady_timer;
    
    static auto now = timer::clock_type::now;
    
    static void coro_sleep(timer::duration delay, yield_context yc) {
        timer(get_associated_executor(yc), delay)
            .async_wait(yc);
    }
    
    int main() {
        static constexpr auto never = timer::time_point::max();
    
        static auto logger = [](auto name) {
            return [name, start = now()](auto const&... args) {
                ((std::cout << name << "\t+" << (now() - start) / 1ms << "ms\t") << ... << args) << std::endl;
            };
        };
    
        boost::asio::io_context ctx;
        spawn(ctx, [log = logger("coro1")](yield_context yield) {
            log("started");
            timer cond(get_associated_executor(yield), 5s);
    
            spawn(yield, [&cond, log = logger("coro2")](yield_context yield) {
                log("started");
    
                cond.async_wait(yield);
                log("condition met");
    
                coro_sleep(1200ms, yield);
                log("signal done");
                cond.expires_at(never);
    
                log("exiting");
            });
    
            for (; cond.expiry() != never; coro_sleep(1s, yield)) {
                log("alive");
            }
    
            log("exiting");
        });
    
        ctx.run();
    }
    

    打印

    coro1   +0ms    started
    coro2   +0ms    started
    coro1   +0ms    alive
    coro1   +1001ms alive
    coro1   +2001ms alive
    coro1   +3001ms alive
    coro1   +4001ms alive
    coro2   +5000ms condition met
    coro1   +5002ms alive
    coro1   +6002ms alive
    coro2   +6200ms signal done
    coro2   +6200ms exiting
    coro1   +7002ms exiting
    

    当然,如果您需要,有很多方法可以共享计时器,但原理是一样的。当您使用多个线程运行执行上下文时,请注意共享资源的同步。

    按照我的措辞,一个简单的改变就可以确保这一点:

    Live On Wandbox

    boost::asio::thread_pool ctx;
    spawn(make_strand(ctx), [log = logger("coro1")](yield_context yield) {
    

    【讨论】:

    • 添加了演示Live On Wandbox
    • 非常感谢@sehe,这真的很有帮助。
    猜你喜欢
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 2020-02-23
    • 2019-08-27
    相关资源
    最近更新 更多