С++20 сопрограмм с ожидаемой пользовательской приостановкой
Я использую С++20 с ожидаемым ускорением для написания асинхронного сервера/клиента. Одной из особенностей сокета boost asio является то, что небезопасно одновременно вызывать async_write для сокета даже с 1 потоком. В основном я пытаюсь избежать ситуации, когда:
вызов и приостановка
не будет мешать другой сопрограмме, вызывающей тот же сокет, т.е.
co_await async_write(sock, buffer(std::string{"data to send"}), use_awaitable);
Ниже приведен псевдокод того, чего я пытаюсь достичь. Я хочу создать точку подвеса внутри
w.Write(msg)
, поставьте в очередь ожидающий/дескриптор, и когда один
async_write
завершена, эта сопрограмма отправит сообщение обратно в
io_context
чтобы возобновить другую сопрограмму. звонивший из
w.Write
должны быть приостановлены до возобновления соответственно.
struct Writer {
std::deque<...> q;
bool write_in_progress = false;
...
awaitable<void> WriteImpl(std::string const&) {
co_await async_write(sock, buffer(std::string{"data to send"}), use_awaitable);
if (!q.empty()) {
auto awaiter = q.pop_front();
post(ctx, []{ awaiter.coro_handle.resume(); });
}
}
awaitable<void> Write(std::string const& msg) {
if (write_in_progress) {
auto awaiter = WriteImpl(msg);
q.push_back(awaiter);
co_await awaiter;
} else {
write_in_progress = true;
co_await WriteImpl(msg);
}
}
};
Writer w{...};
co_await w.Write(msg);
Любое предложение о том, как реализовать это с помощью boost asio 1.76 и awaitable. Глядя на ожидаемую реализацию в boost, она не поддерживает этот нелинейный поток, хотя я не уверен...
Благодарность!
РЕДАКТИРОВАТЬ: Ниже я следую за предложением использовать
steady_timer
.
#include <iostream>
#include <chrono>
#include <coroutine>
#include <boost/asio.hpp>
using namespace boost;
using namespace boost::asio;
awaitable<void> Trigger(steady_timer& timer) {
std::cout << "trigger is running" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
auto n = timer.cancel();
std::cout << "cancelled " << n << " async operatiosns" << std::endl;
co_return;
}
awaitable<void> Process(io_context& ctx, steady_timer& timer) {
std::cout << "from coroutine" << std::endl;
co_spawn(ctx, Trigger(timer), detached);
std::cout << "launched trigger" << std::endl;
co_await timer.async_wait(use_awaitable);
std::cout << "done waiting" << std::endl;
co_return;
}
void Test1() {
io_context ctx;
auto work = require(ctx.get_executor(), execution::outstanding_work.tracked);
steady_timer timer{ctx.get_executor()};
timer.expires_after(std::chrono::hours(24));
co_spawn(ctx, Process(ctx, timer), detached);
ctx.run();
}
int main() {
Test1();
return 0;
}
Когда я запускаю это, я, однако, вообще не вижу напечатанного «готово к ожиданию» ... я делаю что-то не так?
ВК