2

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.

citelao
  • 4,898
  • 2
  • 22
  • 36

1 Answers1

3

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:

citelao
  • 4,898
  • 2
  • 22
  • 36
  • 1
    C++20 is currently lacking any sort of task support for coroutines. While C++/WinRT provides some support (as in this case), I frequently had to look elsewhere when it came to composing tasks. I usually went with Lewis Baker's [CppCoro](https://github.com/lewissbaker/cppcoro) (e.g. [`when_all`](https://github.com/lewissbaker/cppcoro#when_all)). At that time I wasn't aware of `winrt::when_all`. – IInspectable Jan 28 '22 at 21:08
  • 1
    Oh, so your `std::vector` have already been started and are executing in parallel when you get them, something I overlooked – Tom Huntington Jun 22 '22 at 21:41
  • 1
    @TomHuntington exactly! I view `IAsyncAction`s as handles to work that is already queued/executing. So awaiting them in an arbitrary order one-by-one is sufficient. – citelao Jun 23 '22 at 19:04