I have an asynchronous operation by an external library that I can't change, but I can give a callback to. I want to wait for it to finish but without blocking the io_context.
Something like:
// Example callback-based operation
void exampleAsyncOperation(std::function<void(boost::system::error_code)> callback) {
std::thread t([=]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
callback(boost::system::error_code());
});
t.detach();
}
boost::asio::awaitable<void> NRClient::callAsyncOperation() {
std::promise<boost::system::error_code> promise;
auto future = promise.get_future();
example_async_operation([&](boost::system::error_code ec) { promise.set_value(ec); });
future.wait(); // this should be something that won't block the thread
}
Or is there something else I can put in the callback to get this functionality?
You can follow the async-initiation pattern that works with CompletionToken to allow any Asio completion token, so you can await it like
Here's a quick draft of such an implementation:
Most - if not all - of the tricky bits have to do with the fact that you have a non-IO thread, so the invocation of the handler has to be done cautiously.
Here's a live sample Live On Coliru that
Printing
UPDATE
If the entire
exampleAsyncOperationfunction was part of a library, you can use the same technique. The only extra complication comes from passing a move-only type into thestd::functionargument. You need to dynamically allocate something into a copyable type for that:Live On Coliru
For completeness I added some other async work to visibly prove that the
co_awaitdoesn't block: