【发布时间】:2020-10-26 20:15:27
【问题描述】:
我一直在尝试使用 ASIO strands 和 C++20 协程,并注意到奇怪的行为。当我在一个链上生成一个协程,并在其中在第二个链上生成另一个协程并等待它时,当控制权返回到外部协程时,两个链都被阻塞。这是预期的行为吗?如果是这样,我该如何解决这个问题?
以下代码演示了该问题,在 linux 上使用 boost.asio、boost 版本 1.74.0、gcc 版本 10.2.0 进行了测试。
#include <thread>
#include <chrono>
#include <iostream>
#include <boost/asio.hpp>
namespace asio = boost::asio;
using namespace std::chrono_literals;
int main() {
auto ioc = asio::io_context{};
// Create two strands
auto s1 = asio::make_strand(ioc);
auto s2 = asio::make_strand(ioc);
// Prevent the io context from stopping
auto wg = asio::make_work_guard(ioc);
// Over-provision threads just in case
auto w1 = std::jthread{[&]() { ioc.run(); }};
auto w2 = std::jthread{[&]() { ioc.run(); }};
auto w3 = std::jthread{[&]() { ioc.run(); }};
auto w4 = std::jthread{[&]() { ioc.run(); }};
auto w5 = std::jthread{[&]() { ioc.run(); }};
asio::co_spawn(s1, [&]() -> asio::awaitable<void> {
std::cout << "a" << std::endl;
co_await asio::co_spawn(s2, []() -> asio::awaitable<void> {
// Works as intended
// s2 is blocked, s1 is free (b will print)
std::this_thread::sleep_for(2s);
co_return;
}, asio::use_awaitable);
// Expected: s1 is blocked, s2 is free (d will print, e will wait 5s)
// Reality: both s1 and s2 are blocked (after 5s, d and e print at the same time).
// Why?
std::cout << "c" << std::endl;
std::this_thread::sleep_for(5s);
}, asio::detached);
std::this_thread::sleep_for(1s);
asio::co_spawn(s1, []() -> asio::awaitable<void> {
std::cout << "b" << std::endl;
co_return;
}, asio::detached);
std::this_thread::sleep_for(2s);
asio::co_spawn(s2, []() -> asio::awaitable<void> {
std::cout << "d" << std::endl;
co_return;
}, asio::detached);
asio::co_spawn(s1, []() -> asio::awaitable<void> {
std::cout << "e" << std::endl;
co_return;
}, asio::detached);
std::this_thread::sleep_for(10s);
ioc.stop();
}
预期行为:
t__0_1_2_3_4_5_6_7
s1 a_b_c_________e
s2 ______d________
实际行为:
t__0_1_2_3_4_5_6_7
s1 a_b_c_________e
s2 ______________d
【问题讨论】:
-
正确的思维方式是:在协程内链;不是相反。
标签: c++ boost-asio c++20 c++-coroutine