7

I've wrote the following code to test std::async() on functions returning void with GCC 4.8.2 on Ubuntu.

#include <future>
#include <iostream>

void functionTBC()
{
    std::cerr << "Print here\n";
}

int main(void)
{
#ifdef USE_ASYNC
    auto i = std::async(std::launch::async, functionTBC);
#else
    auto i = std::async(std::launch::deferred, functionTBC);
#endif
    //i.get();
    return 0;
}

If i.get(); is uncommented, the message "Print here" always exists; however, if i.get(); is commented out, "Print here" exists if and only if USE_ASYNC is defined (that is, std::launch::async always leads to message printed out while std::launch::deferred never).

Is this guaranteed behavior? What's the correct way to ensure the asynchronous call returning void to be executed?

timrau
  • 22,578
  • 4
  • 51
  • 64
  • 4
    If you ask for a deferred launch and never call .get on that future, your function will never be executed. This has nothing to do with the function returning void or any other type. – sbabbi May 29 '15 at 16:56

1 Answers1

9

std::launch::deferred means "do not run this until I .wait() or .get()".

As you never .get() or .wait()ed, it never ran.

void has nothing to do with this.

For std::launch::async, the standard states that the returned future's destructor (~future) will block until the task is complete (ie, has an implicit .wait()). This is violated by MSVC on purpose, because they disagreed with that design decision, and they are fighting to change the standard: in practice, this means that you cannot rely on any behavior at all from std::launch::async returned future if you want to future-proof your code.

Without implicit wait in ~future, it would be indeterminate if it actually invoked the function when main exited. It would either have happened, or not. Possibly you could invoke UB by having still-active threads at the end of main.

You may wonder what use deferred has: you can use it to queue up a computation for lazy evaluation.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • If I just drop the return value of `std::async()` (remove the `auto i = ` in my snippet), the `std::launch::deferred` version is still skipped. Doesn't this violate "`~future` will block until the task completes"? – timrau May 29 '15 at 17:05
  • "~future will block until the task completes" doesn't apply in this case, because of std::launch::deferred. Suggest you pick up a copy of Meyer's "Effective Modern C++", see Item 38. – kfsone May 29 '15 at 17:18
  • 1
    @timrau The note about `~future` blocking only applies when you `std::async( std::launch::async`. Note that calling `std::async( std::launch::async` without storing the return value causes it to be destroyed at the end of the statement, so the main thread blocks until the async task is complete *on that very line*. Storing it in `auto i=` will make the block occur at the end of the scope. Moving the returned `future` to another `future` will defer the block until the future that stores the state is finally destroyed. – Yakk - Adam Nevraumont May 29 '15 at 17:24
  • @Yakk Sorry, I accidentally missed the condition "For `std::launch::async`". – timrau May 29 '15 at 17:33
  • 2
    MSVC 2015's `async` [now returns blocking futures](http://blogs.msdn.com/b/vcblog/archive/2014/06/06/c-14-stl-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1.aspx), after the proposed change failed to pass in full committee. – T.C. May 29 '15 at 21:54
  • @T.C. Did they modify the page? I can't find either `async` or `promise` word in the link. – cppBeginner Dec 06 '17 at 09:58
  • 1
    @cppBeginner http://web.archive.org/web/20160112225646/http://blogs.msdn.com/b/vcblog/archive/2014/06/06/c-14-stl-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1.aspx – T.C. Dec 06 '17 at 11:29