微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

等待其他协程中的计时器Asio

如何解决等待其他协程中的计时器Asio

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

解决方法

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

我能想到的最简单的方法是从 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) {

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。