Stephan Dollberg
Stephan Dollberg

Reputation: 34608

std::async won't spawn a new thread when return value is not stored

Consider I have lamba foo which just does some stuff and doesn't need to return anything. When I do this:

std::future<T> handle = std::async(std::launch::async, foo, arg1, arg2);

Everything runs fine and the lamba will be spawned in a new thread. However, when I don't store the std::future which the std::async returns, the foo will be run in the main thread and block it.

std::async(std::launch::async, foo, arg1, arg2);

What am I missing here?

Upvotes: 18

Views: 4805

Answers (3)

etoricky
etoricky

Reputation: 691

Why blocking?

  1. std::async(); returns std::future temporary object
  2. temporary object is destroyed immediately, calling desctructor.
  3. std::future destructor is blocking. It is bad and troublesome.

Why assigning is ok?

By assigning to a variable, the returned object is not destroyed immediately, but later, until end of scope of your calling code.

Code Example: main1 is ok. main2 and main3 are equivalently blocking the main thread.

void forever() {
    while (true);
}

void main1() {
    std::future<void> p = std::async(std::launch::async, forever);
    std::cout << "printing" << std::endl; // can print, then forever blocking
}

void main2() {
    std::async(std::launch::async, forever);
    std::cout << "printing" << std::endl; // forever blocking first, cannot print
}

void main3() {
    {std::future<void> p = std::async(std::launch::async, forever);}
    std::cout << "printing" << std::endl; // forever blocking first, cannot print
}

Take a look at cplusplus.com

Return value of std::async When launch::async is selected, the future returned is linked to the end of the thread created, even if its shared state is never accessed: in this case, its destructor synchronizes with the return of fn. Therefore, the return value shall not be disregarded for asynchronous behavior, even when fn returns void.

Upvotes: 3

Wojciech Cierpucha
Wojciech Cierpucha

Reputation: 810

From just::thread documentation:

If policy is std::launch::async then runs INVOKE(fff,xyz...) on its own thread. The returned std::future will become ready when this thread is complete, and will hold either the return value or exception thrown by the function invocation. The destructor of the last future object associated with the asynchronous state of the returned std::future shall block until the future is ready.

In

std::async(std::launch::async, foo, arg1, arg2);

The returned future is not assigned anywhere and its destructor blocks until foo finishes.

Upvotes: 20

Micha Wiedenmann
Micha Wiedenmann

Reputation: 20853

I would like to add a link to an article by Herb Sutter on async and ~future in which he argues that futures should never block.

Upvotes: 6

Related Questions