我有一个异步函数,其中包含一个回调函数,可用作协程,与
asio
中的示例完全相同:
https://github.com/chriskohlhoff/asio/blob/fa27820c05afd740fa2adc1ecfb9da5afe026443/asio/src/examples/cpp20/operations/c_callback_wrapper.cpp
在此示例中,基于 C 的 API 函数
read_input
被 async_read_input
包装,并且可以像这样使用:
co_await async_read_input("Enter your name", asio::use_awaitable);
问题是,我的
read_input
不是线程安全的(我从多个线程调用 io_context::run
)。据我了解,在这种情况下 asio::strand
应该是有用的,但我不知道如何。如果我做类似的事情
co_await async_read_input("Enter your name", asio::bind_executor(strand, asio::use_awaitable));
据我了解,它的做法与我想要的相反,使完成按一定顺序发生,同时仍然让
read_input
并行运行。如果我使用post
/dispatch
/defer
(我什至知道如何/如果可能的话)我不能co_await
它。我还想co_await
它。
链不会阻止操作并发运行。事实上,这与 Asio 的整个设计背道而驰:它的存在是为了促进与(本质上)异步外设或服务的交互。实际上,许多异步操作只能同时运行,例如当它们发生在硬件中时。
您可以使用链来避免并发启动操作,但这并不意味着您不会立即启动多个并发操作,除非您还确保先前的操作已提前完成。这通常意味着某种排队。
我认为您描述的应用程序归结起来是这样的:
read_input
”),这样世界其他地方就可以简单地将其视为真正的异步服务,只需延迟较高,具体取决于已挂起的调用数量。非常简单地说,可能会转化为:
void read_input(char const* prompt, void (*cb)(void*, char const*), void* arg) {
std::thread([prompt = std::string(prompt), cb, arg] {
static std::mutex mx;
std::string line;
{
std::lock_guard lk(mx);
std::cout << prompt << ": ";
std::cout.flush();
std::getline(std::cin, line);
}
cb(arg, line.c_str());
}).detach();
}