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.