Reputation: 527
I tried to test how std::shared_future
is shared between different threads as these threads all calls its wait()
function, and wake up after its signal
is called. As below:
#include <iostream>
#include <future>
using namespace std;
int main() {
promise<void> p, p1, p2;
auto sf = p.get_future().share(); // This line
auto f1 = [&]() {
p1.set_value();
sf.wait();
return 1;
};
auto f2 = [&]() {
p2.set_value();
sf.wait();
return 2;
};
auto ret1 = async(launch::async, f1);
auto ret2 = async(launch::async, f2);
p1.get_future().wait();
p2.get_future().wait();
p.set_value();
cout << ret1.get() << ", " << ret2.get();
return 0;
}
The program prints 1, 2
and works fine.
Then I changed the line of auto sf = p.get_future().share();
into auto sf = p.get_future()
using oridinay future
object, not the shared
version, compile and run. I got the same result: while I expected that for the non-shared version, only 1 thread will successfully wait
and return while other threads will hang. But seems still the program runs OK.
So my question is: when do we need to use std::shared_future
instead of std::future
? Or it's just an object like std::shared_ptr
, as a simple wrapper of std::future
so that it could be passed around?
I mean is there any case that non-shared future doesn't fulfill the need or scenario. Would you help to explain?
Upvotes: 2
Views: 1438
Reputation: 5
One copy of std::shared_future cannot be used from different threads except for copying. It is necessary that each thread has its own copy of std::shared_future.
https://en.cppreference.com/w/cpp/thread/shared_future
Access to the same shared state from multiple threads is safe if each thread does it through its own copy of a shared_future object.
Upvotes: 0
Reputation: 19123
The "shared" part of shared_future
is not about the waiting but getting.
I expected that for the non-shared version, only 1 thread will successfully wait and return while other threads will hang.
No, this is completely safe, you can wait on a future from as many threads as you want (it is a const member, hence thread-safe) and all must unblock when the result is set. But be warned that wait()
cannot be called after someone called get()
.
The difference is in how you get the results. Remember, std::future
stands for a future result set by std::promise
.
std::future::get()
returns by value. It can only be called once and thus only from one thread.std::shared_future::get()
returns a const reference. It can be called many times from multiple threads. Of course be careful about the thread-safety of the underlying object - whether its methods are really thread-safe.Furthermore std::shared_future
can be cloned and multiple such objects can refer to a single shared state, i.e. linked to a single promised object. The shared state exists as long as some future/promise points to it, like std::shared_ptr<State>
.
In your case, you are slightly misusing std::shared_future sf
, each thread that awaits the result should get its own clone. That way, its lifetime is safe. The envisioned workflow is:
std::promise
is created, the [first] future
is obtained from it.I mean is there any case that non-shared future doesn't fulfill the need or scenario. Would you help to explain?
Having two consumer threads, both awaiting the result. std::future
would require for exactly one thread to call get
and somehow share that result with the other. Although both could have called wait()
. On the other hand std::shared_future
allows both to "view" the result since it is const. Yes, one has to copy the result if it needs to be passed around but that is unavoidable anyway.
Upvotes: 5