Writing a custom async function using ASIO

70 Views Asked by At

I'm working on a async udp server for a multiplayer game. It is a personal project and for education. I'm using ASIO standalone and C++20, mainly relying on coroutines. For the past couple of days I've been trying to implement a function that works similarly to 'async_read' for example (already defined in ASIO). This function should give back control to the io_context if a queue (which is passed as a parameter) is empty, or take control back if the queue contains at least one element. I hope the code snippets clarify what I'm trying to do.

I want to use it this way:

asio::awaitable<void> udp_server::process() {
    // process messages from queue for the entire lifetime of the server
    while (true) {
        // pause here until there is a message in the queue
        // and do other work meanwhile (read from clients, compute stuff, etc)
        co_await async_wait_for_queue(coro_queue_in, asio::use_awaitable);
        
        // get the message in front of the queue
        auto& msg = coro_queue_in.front();
        coro_queue_in.pop();

        // and process it (for now, just print it)
        std::cout << msg << "\n";
        // and then repeat this all over again
    }
}

So while the server is running I want to have a bunch of tasks in the io_context queue which read data from each client and also a task which processes the incoming messages.

struct async_queue_implementation {
    std::queue<owned_message>& queue_;
    template<typename Self> void operator()(Self& self) {
        if (!queue_.empty()) {
            self.complete();
        }
    }
};

template<typename CompletionToken>
auto async_wait_for_queue(std::queue<owned_message>& queue,
    CompletionToken&& token) -> 
    decltype(asio::async_compose<CompletionToken, void()>
    (std::declval<async_queue_implementation>(), token))
{
    return asio::async_compose<CompletionToken, void()>
        (async_queue_implementation{ queue }, token);
}

I've tried this but it doesn't work. It compiles, it runs, but it doesn't ever get past line 3 from the previous code snippet. It's as if the task never resumes, but it should, because I can confirm that the queue receives new elements and so it is not empty.

Please help me implement such functionality using ASIO coroutines. I feel like I've gotten extremely close with the code above but something is still missing.

0

There are 0 best solutions below