3

Cppreference says about std::future that

The creator of the asynchronous operation can then use a variety of methods to query, wait for, or extract a value from the std::future.

Who is the creator of the asynchronous operation? Is it the thread that creates the std::future object, or any thread that has access to that object? In the end, my question is if non-creators can also use the get method on the std::future.

In particular, I would like to know if this piece of code is correct:

std::future<int> foo;
std::thread t([&foo](){ 
    foo = std::async(std::launch::async, [](){ return 4; });
});
t.join();
int n = foo.get();  // can the main thread call foo.get()?
ChronoTrigger
  • 8,459
  • 1
  • 36
  • 57
  • Can you explain what your concern is regarding the snippet your provided? Which part or line are you unsure about? – François Andrieux Dec 13 '17 at 16:22
  • 1
    The same as the owner of any other object. In that snippet, the "stack frame" in which `foo` is declared – Caleth Dec 13 '17 at 16:24
  • If it is called in main you are correct otherwise it is in the scope of declaration – Jake Freeman Dec 13 '17 at 16:25
  • You can do `foo.get()` as `foo` is in scope. But your `t.join()` makes sure that it is already finished. – Shiv Dec 13 '17 at 16:27
  • 1
    My doubts are if other "non-creators" can also use the `std::future` object. – ChronoTrigger Dec 13 '17 at 16:29
  • who is the owner of `int`? who is the owner of `std::string`? who is the owner of `std::ifstream`? – David Haim Dec 13 '17 at 16:30
  • @David, yes but to be fair the documentation of std::string doesn't talk about "the owner" of the std::string. – Gem Taylor Dec 13 '17 at 16:33
  • I should have used the term "creator" instead of "owner" in the title of the question. – ChronoTrigger Dec 13 '17 at 16:34
  • and where does it talk about the ownership of `std::future`? – David Haim Dec 13 '17 at 16:34
  • I can definitively see how the wording could be confusing. Ownership has several other meanings, which are more complex than just scope resolution. For example, smart pointers exist to make the semantics ownership of objects explicit. And only the thread that owns a mutex lock is allowed to unlock it. I'm fairly certain that `std::future` is not one of those cases and that the documentation just refers to anything that has access to it, but I can't find a source to cite. – François Andrieux Dec 13 '17 at 16:42

1 Answers1

1

Who is the creator of the asynchronous operation? Is it the thread that creates the std::future object, or any thread that has access to that object?

There are essentially 3 things that can create such "asynchronous operation":

  • std::async
  • std::promise
  • std::packaged_task

These "creators" create a so called shared state, in which the std::future obtained equally shares access to. The shared state is where the results of such operation is stored. both the provider (an std::async, std::promise, or std::packaged_task object) and the consumer (the std::future obtained) accesses the shared state in a thread safe manner, its an implementation detail you shouldn't be bothered about.

In the end, my question is if non-creators can also use the get method on the std::future.

Of cause; An "asynchronous operation" typically takes place in a different thread of execution, and the purpose of std::future is to safely query and access the results of such "asynchronous operation" happening somewhere else, without you explicitly using any extra synchronization mechanism.

In particular, I would like to know if this piece of code is correct:

std::future<int> foo;
std::thread t([&foo](){ 
    foo = std::async(std::launch::async, [](){ return 4; });
});
t.join();
int n = foo.get();  // can the main thread call foo.get()?

While this "particular short snippet" doesn't seem to invoke a race condition; It's not in any way a good code. At any point in time, the std::future to a shared state obtained from an "asynchronous operation" should not be used by multiple thread at a time.

In your case, the get() and the assignment operator isn't thread-safe. And sooner or later, this code will quickly grow to invoke a race-condition

One more note, the use of a std::thread in your code isn't needed, in practice a decent implementation will create a new thread or use a thread pool when your launch policy is std::launch::async. Hence you should just do:

std::future<int> foo = std::async(std::launch::async, [](){ return 4; });
int n = foo.get();
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
  • The `thread` of the snippet is for illustration purposes only. However, I don't understand why the snippet can create a race condition. Doesn't `t.join()` protect `get` from racing against `operator=`? – ChronoTrigger Dec 13 '17 at 19:34
  • 1
    @ChronoTiger, there's no race condition at that snippet, however, you are misusing of both `std::thread` and `std::future`. There's a very high chance that if you continue writing code that way, you'll introduce a race condition sooner than you know. Please reread my answer carefully – WhiZTiM Dec 14 '17 at 06:18
  • Now I understand you meant that `get` and the `assignment operator` are not thread-safe operations in general, and not in my specific snippet. I know I could just wrote `int n = 4`, but that does not exemplify the question I wanted to ask with that MWE. I appreciate your answer. Could you tell me if you agree with @David Haim's answer above, which says the snippet shows undefined behavior? – ChronoTrigger Dec 15 '17 at 16:18
  • @ChronoTrigger, No, I do not agree with David's answer that the snippet invokes Undefined Behavior. Note that: `t.join()` synchronizes with the completion of the thread `t` - All writes done in the thread `t` is guaranteed to be complete and visible to the thread waiting for the `join()` (after the `join()` is returns without an exception). See a [**very similar question to yours**](https://stackoverflow.com/questions/29684369/implicit-synchronization-when-creating-joining-threads). And see [**this**](https://stackoverflow.com/questions/27109314/does-joining-a-stdthread-flush-memory) also... – WhiZTiM Dec 15 '17 at 23:49