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?
CodePudding user response:
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.- The promise is given to the producer, consumers do not know about it.
- The future is given to [each] consumer [which can clone it and pass it along if necessary].
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.