С++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;
}

Когда я запускаю это, я, однако, вообще не вижу напечатанного «готово к ожиданию» ... я делаю что-то не так?

ВК

0 ответов

Другие вопросы по тегам