c++uwpc++-winrtc++-coroutinecppwinrt

How can I await multiple awaitables/IAsyncActions in C++/WinRT (`Promise.all` equivalent)?


Is there an equivalent to JavaScript's Promise.all in C++ or C++/WinRT for awaitables (or just Windows.Foundation.IAsyncAction)?

For example, I am trying to gather multiple IAsyncActions and continue when all of them have completed. For now I'm starting each action and then awaiting them one by one in a simple loop:

winrt::IAsyncAction AwaitMultiple(std::vector<winrt::IAsyncAction> actions)
{
    for (const auto& action : actions)
    {
        co_await action;
    }
}

// ... somewhere else...

winrt::IAsyncAction MyFunctionAsync()
{
    std::vector<winrt::IAsyncAction> actions{};
    actions.push_back(/* some function that generates an IAsyncAction */);
    actions.push_back(/* some function that generates an IAsyncAction */);
    actions.push_back(/* some function that generates an IAsyncAction */);
    // ... etc...

    co_await AwaitMultiple(actions);

    // ... do other stuff...
}

Is there a better way to do this? Is there a language way?

Disclaimer: I work for Microsoft.


Solution

  • As is often the case, there is indeed a C++/WinRT function for almost this case: winrt::when_all(T... async) (it is not currently documented on Advanced concurrency and asynchrony with C++/WinRT).

    If you have modern C++/WinRT, you can await multiple actions at once:

    winrt::IAsyncAction MyFunctionAsync()
    {
        const auto myAction = /* function that generates an IAsyncAction */;
        const auto myAction2 = /* function that generates an IAsyncAction */;
        const auto myAction3 = /* function that generates an IAsyncAction */;
    
        // magic!
        co_await winrt::when_all(myAction, myAction2, myAction3);
    }
    

    This is similar to the Parallel Pattern Library (PPL) when_all.

    This doesn't solve the std::vector<winrt::IAsyncAction> above, but luckily Raymond Chen has some posts about that:

    A customer wanted to know how they could pass a std::vector of IAsyncAction objects to the when_all function.

    std::vector<IAsyncAction> actions = get_actions();
    for (auto&& action : actions) co_await action;
    

    [... some more content about trying to wrap that in an overload for winrt::when_all...]

    Synthesizing a when_all coroutine from pieces you already have


    See also: