C++ program unexpectedly blocks / throws

Woj*_*tek 9 c++ multithreading c++11

I'm learning about mutexes in C++ and have a problem with the following code (taken from N. Josuttis' "The C++ Standard Library").

I don't understand why it blocks / throws unless I add this_thread::sleep_for in the main thread (then it doesn't block and all three calls are carried out).

The compiler is cl.exe used from the command line.

#include <future>
#include <mutex>
#include <iostream>
#include <string>
#include <thread>
#include <chrono>

std::mutex printMutex;

void print(const std::string& s)
{
    std::lock_guard<std::mutex> lg(printMutex);

    for (char c : s)
    {
        std::cout.put(c);
    }
    std::cout << std::endl;
}

int main()
{
    auto f1 = std::async(std::launch::async, print, "Hello from thread 1");
    auto f2 = std::async(std::launch::async, print, "Hello from thread 2");

    // std::this_thread::sleep_for(std::chrono::seconds(1));

    print(std::string("Hello from main"));       
}
Run Code Online (Sandbox Code Playgroud)

Nia*_*all 11

I think what you are seeing is an issue with the conformance of the MSVC implementation of async (in combination with future). I believe it is not conformant. I am able to reproduce it with VS2013, but unable to reproduce the issue with gcc.

The crash is because the main thread exits (and starts to clean up) before the other two threads complete.

Hence a simple delay (the sleep_for) or .get() or .wait() on the two futures should fix it for you. So the modified main could look like;

int main()
{
    auto f1 = std::async(std::launch::async, print, "Hello from thread 1");
    auto f2 = std::async(std::launch::async, print, "Hello from thread 2");

    print(std::string("Hello from main"));       

    f1.get();
    f2.get();
}
Run Code Online (Sandbox Code Playgroud)

Favour the explicit wait or get over the timed "sleep".

Notes on the conformance

There was a proposal from Herb Sutter to change the wait or block on the shared state of the future returned from async. This may be the reason for the behaviour in MSVC, it could be seen as having implemented the proposal. I'm not sure what the final result was of the proposal was or its integration (or part thereof) into C++14. At least w.r.t. the blocking of the future returned from async it looks like the MSVC behaviour did not make it into the specification.

It is interesting to note that the wording in §30.6.8/5 changed;

From C++11

a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined

To C++14

a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined, or else time out

I'm not sure how the "time out" would be specified, I would imagine it is implementation defined.