等待其他协程中的计时器(Asio)
Wait for timer in other coroutine (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(“分叉”,如果你愿意的话),因为为什么不呢:
#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
当然,如果你需要,共享定时器的方法有很多种,但原理都是一样的。当您使用多个线程到 运行 执行上下文时,请注意共享资源的同步。
按照我的措辞方式,一个简单的改变就可以确保这一点:
boost::asio::thread_pool ctx;
spawn(make_strand(ctx), [log = logger("coro1")](yield_context yield) {
使用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(“分叉”,如果你愿意的话),因为为什么不呢:
#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
当然,如果你需要,共享定时器的方法有很多种,但原理都是一样的。当您使用多个线程到 运行 执行上下文时,请注意共享资源的同步。
按照我的措辞方式,一个简单的改变就可以确保这一点:
boost::asio::thread_pool ctx;
spawn(make_strand(ctx), [log = logger("coro1")](yield_context yield) {