如何用Strand实现C++20协程中d_print的串行执行?
问题描述
现有代码
#include <boost/asio.hpp> #include <chrono> #include <iostream> namespace io = boost::asio; class test { public: test(io::any_io_executor e) : exe{ std::move(e) } {} io::awaitable<void> delay(size_t sec) { io::steady_timer t{ exe }; t.expires_after(std::chrono::seconds{ sec }); co_await t.async_wait(io::use_awaitable); } io::awaitable<void> print_and_delay(int num) { std::cout << num << '\n'; co_await delay(1); } io::awaitable<void> d_print() { co_await print_and_delay(1); co_await print_and_delay(2); co_await print_and_delay(3); } void start() { for (size_t i = 0; i != 3; ++i) { io::co_spawn(exe, d_print(), io::detached); } } protected: io::any_io_executor exe; }; int main() { io::io_context ctx; test t{ ctx.get_executor() }; t.start(); ctx.run(); return 0; }
当前输出
1 1 1 (delay 1 second) 2 2 2 (delay 1 second) 3 3 3 (delay 1 second)
需求说明
需要让d_print协程串行执行:同一时间仅一个d_print协程运行,期望输出如下(每行间隔1秒):
1 2 3 1 2 3 1 2 3
疑问
是否可以通过使用strand实现该需求?希望能在三个print_and_delay调用外添加类似synchronized(st) {}的机制,让后续协程等待当前运行的协程完成后再执行。
解决方案
可以用Boost.Asio的strand实现这个串行化需求。strand是一种执行器,能保证提交给它的任务按顺序执行,同一时间只有一个任务在运行,刚好符合你要的同步效果。
修改后的代码
#include <boost/asio.hpp> #include <chrono> #include <iostream> namespace io = boost::asio; class test { public: test(io::any_io_executor e) : strand_{ io::make_strand(std::move(e)) } {} io::awaitable<void> delay(size_t sec) { io::steady_timer t{ strand_ }; t.expires_after(std::chrono::seconds{ sec }); co_await t.async_wait(io::use_awaitable); } io::awaitable<void> print_and_delay(int num) { std::cout << num << '\n'; co_await delay(1); } io::awaitable<void> d_print() { // 绑定strand,确保后续操作串行执行 co_await io::post(strand_, io::use_awaitable); co_await print_and_delay(1); co_await print_and_delay(2); co_await print_and_delay(3); } void start() { for (size_t i = 0; i != 3; ++i) { io::co_spawn(strand_, d_print(), io::detached); } } protected: io::strand<io::any_io_executor> strand_; }; int main() { io::io_context ctx; test t{ ctx.get_executor() }; t.start(); ctx.run(); return 0; }
关键修改说明
- 替换执行器为strand:把原
exe成员换成strand_,通过io::make_strand基于传入的执行器创建strand,strand会强制任务按提交顺序串行执行。 - d_print开头绑定strand:在
d_print协程开头调用co_await io::post(strand_, io::use_awaitable),这一步相当于获取strand的"执行权限",确保后续的print_and_delay调用都在strand的串行调度下完成。 - co_spawn使用strand:启动协程时直接传入strand作为执行器,确保整个协程的调度都受strand控制,避免额外的并发调度。
这样修改后,三个d_print协程会按顺序执行:第一个完成1→2→3的输出后,第二个才开始,以此类推,完全符合期望的输出效果。
内容的提问来源于stack exchange,提问作者aleck099
相关产品推荐
相关产品推荐

