Best way to keep track of pending IAsyncActions
Closed this issue · 4 comments
Version
No response
Summary
This isn't a bug. Just a question.
Let's say you have a long-running application that fires off a bunch of methods on the threadpool using winrt::resume_background()
. And then when it's time to close the app, you'd like to wait for any in-flight tasks to finish up.
I understand that there are functions like winrt::when_all
that allow you to wait on a bunch of IAsyncActions
. Or you can loop through a vector of IAsyncActions
and co_await them, as discussed here.
But my question is: what's the best strategy for keeping a hold on your pending IAsyncActions
so that you know the ones to wait on when it's time to quit? Is there a specific class or function for that?
Granted, you could just store each and every IAsyncAction
in a vector, but for a long-running app that may fire off hundreds or thousands of tasks, it seems like that vector would get really large and inefficient--especially since, as a practical matter, there are probably only one or two outstanding tasks to wait on when it's time to quit.
Perhaps there could be a class that acts like a vector for storing IAsyncActions
, except it would remove each one upon completion. But that would monopolize the IAsyncAction
's delegate, wouldn't it?
Or is it better to use a latch (i.e., reverse semaphore) in this situation?
Thanks for any information or guidance.
Reproducible example
No response
Expected behavior
No response
Actual behavior
No response
Additional comments
No response
I have been doing the following:
std::mutex m_asyncSetLock;
std::unordered_set<winrt::Windows::Foundation::IAsyncAction> m_inflightAsync;
void Foo::registerInflightAsync(winrt::Windows::Foundation::IAsyncAction async)
{
async.Completed({ this, &Foo::unregisterInflightAsync });
std::scoped_lock guard(m_asyncSetLock);
m_inflightAsync.insert(std::move(async));
}
void Foo::unregisterInflightAsync(const winrt::Windows::Foundation::IAsyncAction& async, winrt::Windows::Foundation::AsyncStatus status)
{
std::scoped_lock guard(m_asyncSetLock);
m_inflightAsync.erase(async);
}
It does, as you say, monopolize the Completed handler.
Thanks a lot. So then how do you use it at the end of an application if you can’t co_await the actions?
At the end of the application, I just hard-block with .get()
on each action consecutively.
Oh yeah, that makes sense. Thanks again.