Search code examples
c++synchronizationstdasync

Is this code correctly synchronized?


I wonder if this code is fine or not:

#include <iostream>
#include <future>
struct Foo
{
    Foo()
        :m_a(0)
    {
    }

    int m_a;
};

int main()
{
    Foo f;
    auto handle =
        std::async( std::launch::async, 
                [](Foo* f) { std::cout << f->m_a << '\n'; } ,
                &f
              );

    handle.get();
}

I believe m_a should be protected by a synchronization mechanism but my colleague says it is not necessary.

EDIT: To clarify my question: I am worried that the STORE operation from the constructor of Foo() happens after the LOAD operation from the other thread. I can't see what mechanism prevents the compiler from executing those instruction in this order.

EDIT: I believe an enthusiastic compiler could decide to inline the constructor, and delay the STORE operation for after the CALL operation to std::async. In which case the second thread could access m_a before it has been committed to memory.


Solution

  • Yes, this is correctly synchronised.

    From the specification for async, C++11 30.6.8/5:

    the invocation of async synchronizes with the invocation of f.

    where f is the function argument to async (the lambda in your example).

    Initialisation of f.m_a is sequenced before the call to async, and therefore before any access by the asynchronous function.

    Furthermore,

    the completion of the function f is sequenced before the shared state is made ready.

    so the access must happen before the call to get() returns, and therefore before the object is destroyed.