4

Maybe I'm missing the correct usage of the new std::async in C++11, however this statement (over at cppreference.com):

If the async flag is set (i.e. policy & std::launch::async != 0), then async executes the function f on a separate thread of execution as if spawned by std::thread(f, args...), except that if the function f returns a value or throws an exception, it is stored in the shared state accessible through the std::future that async returns to the caller.

Makes me think that my thread should start immediately with this statement:

std::async(std::launch::async, MyFunctionObject());

Without having to wait for calling the std::future::get(). This seems to not be the case (compiling with MSVC 13). If this is not triggered by this statement itself, how should this get triggered if I don't care about the return value of the std::future object?

Example:

#include <thread>
#include <iostream>
#include <array>
#include <future>

static std::mutex write_mutex;

class Cpp11Threads {
public:
    // Function operator for Function-Object
    void operator()() {
        const int num_threads = 50;

        // Static std array
        std::array<std::thread*, num_threads> worker_threads;

        // Range based
        for (std::thread*& thread : worker_threads) {

            // Lambda expression
            thread = new std::thread(
                [] {
                    static int i = 0;
                    write_mutex.lock();
                    std::cout << "Hello, I am happy Std thread #" << i++ << std::endl;
                    write_mutex.unlock();
                });
        }

        for (std::thread*& thread : worker_threads) {
            thread->join();
            delete thread;

            // nullptr instead of NULL
            thread = nullptr;
        }
    }
};

int main() {
    std::async(std::launch::async, Cpp11Threads());
    return 0;
}
whoan
  • 8,143
  • 4
  • 39
  • 48
Danny A
  • 323
  • 1
  • 4
  • 14
  • How do you determine whether the thread has started or not? I am asking because this incantation of `std::async` has interesting semantics (i.e. it is blocking). – juanchopanza Jan 09 '14 at 14:52

2 Answers2

9

The first thing you have to know is that MSVC std::async does not conform to the C++11 standard.

Under the C++11 standard, std::async's std::future return value blocks until the std::async completes.

MSVC's implementation does not. This makes their std::async seemingly more friendly to use, but in practice it is quite tricky.

However, as std::async's behavior is described in terms of std::thread, we can look at what happens when you kick off a std::thread and fail to clean it up. The resulting std::thread is effectively detached. Once you exit main, the C++ standard does not specify what happens to such std::threads, leaving it up to your particular implementation.

Based off some quick research, when a MSVC windows program goes off the end of main, the threads are terminated.

In short, your program needs to resynchronize with the threads you launched in some way or another, so that they can complete their tasks, and prevent the main program from exiting main. An easy way to do that is to store the returned std::future from your async task, and wait on it before main exits.

If you had a conforming C++11 compiler, your attempted async would fail to be asynchronous, as it would block immediately upon the destruction of the anonymous std::future it returned.

Finally, note that launched threads and the like may not be scheduled to run immediately after creation. How and when they run is not predictable.

The C++11 concurrency primitives are merely primitives. Many of them have quirky behavior, like the fact that a std::thread calls terminate if it is destroyed without being detached or joined, and async's tendency to block if you don't store the future. They can be used for simple tasks, or for writing higher level libraries, but they are not user friendly.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • "If you had a conforming C++11 compiler, your attempted `async` would fail to be asynchronous, as it would block immediately upon the destruction of the anonymous std::future it returned." This is exactly what I thought, when the `future` goes out of scope it would block, waiting for the thread to finish (or kick it off). Bummer on MSVC's part. – Danny A Jan 09 '14 at 16:39
2

I'm not proficient with C++11 but AFAIK each program has a main thread and it is the thread in which your main() function executes. When the execution of that thread finishes, the program finishes along with all its threads. If you want your main thread to wait for other threads, use must use something like

pthread_join

in a linux environment (if you created your thread manually), or exactly

std::future::get()

in this specific case.

Exiting main will kill your threads and in your case probably prevent you from launching the thread at all

Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • 1
    You're right. Since my main thread isn't waiting by using the future::wait() the threads don't get the chance to print. Semi-obvious, but not intuitive (adding a `_sleep(10000)` after the `async` had them all printing like a charm), thanks. – Danny A Jan 09 '14 at 15:05
  • 1
    @DannyA your code should block until the `async` is done, according to C++11. – juanchopanza Jan 09 '14 at 15:10
  • 1
    @DannyA Oh, it seems [VS might have a bug](http://stackoverflow.com/questions/12508653/what-is-the-issue-with-stdasync) which means the call is non-blocking. – juanchopanza Jan 09 '14 at 15:12
  • Are we sure it should block even if nobody's collecting the std::future value? I tested it but I'm not proficient with C++11 code as I already stated – Marco A. Jan 09 '14 at 15:15
  • 2
    @DavidKernin basically, in C++11 the returned `future` waits for completion in its destructor. Since OP's code doesn't assign the call to anything, the call blocks. If you assign to a future you gan decide when to block. – juanchopanza Jan 09 '14 at 15:20