I want to model a problem where one asynchronous operation produces some T
and then there are multiple calls to get that T
on various threads. These calls will be repeated often, so even on one thread, that T
will be requested multiple times.
I first thought about using std::promise
/ std::future
for this, ie,
// Declaration
std::promise<T> p;
std::future<T> f = p.get_future();
// Producer code (different function)
p.set_value(...);
// Consumer code (different function; will be called repeatedly from different threads)
return f.get();
The problem here is that obivously future::get
is a one-shot operation which cannot be repeated, so I thought about shared_future::get()
. But shared_future
mentions in its documentation:
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.
This seems weird, as shared_future
only has const methods, which should always be thread-safe, so I don't see any necessity for this own copy
requirement. I don't know how many threads there will be, so I cannot create one shared_future
per thread. The consumer code can be called repeatedly on any thread. What is the best way to do this?
Can I just create a shared_future
copy on the fly whenever somebody wants to consume the T
? Ie:
// Declaration
std::promise<T> p;
std::shared_future<T> f = p.get_future();
// Producer code (different function)
p.set_value(...);
// Consumer code (different function; will be called repeatedly from different threads)
std::shared_future<T> fCopy = f; // Make a private copy of f on the stack.
return fCopy.get(); // Use the copy to get the T
Is this how it should be done? Is copy-constructing shared_future
thread-safe? Will this have good performance, or should I do it differently?
Apologies for my wrong suggestion in the comment replies, but I think what you want is a std::latch
. Initialize to 1, and have anything waiting on it call the wait()
method to wait forever until it gets made, or try_wait()
if you don't want a forever wait.
Here's where I'm coming from:
int main(int argc, char* argv[])
{
std::latch mylatch{ 1 };
std::unique_ptr<int> common_source{};
std::mutex sync_cout{};
auto myTester = [&]() {
mylatch.wait();
std::lock_guard locker{ sync_cout };
cout << "Through the latch, value is: " << *common_source << endl;
};
// Start the waiting threads
std::vector<std::thread> threads;
for (int i = 0; i < 5; i++)
{
std::thread mythread{ myTester };
threads.push_back(std::move(mythread));
}
cout << "Threads started" << endl;
common_source = std::make_unique<int>(15);
mylatch.count_down();
std::this_thread::sleep_for(100ms);
{
std::lock_guard locker{ sync_cout };
cout << "After count_down, starting a fresh thread to show it is let through" << endl;
}
{
std::thread mythread{ myTester };
threads.push_back(std::move(mythread));
}
// Wait for the threads to finish
for (auto& curThread : threads)
{
curThread.join();
}
cout << "All threads down" << endl;
}
Adapt as you see fit. Change the unique_ptr
to whatever type you want to distribute, and obviously lock for copying it, rather than just outputting a number. And if for some reason a "handler" comes in late (after it's already counted down) it's just let through, just as you'd want, rather than waiting forever, as I show in my example.
By default, any function defined in the C++ standard library is considered to be thread-safe relative to some object if that function takes that object by pointer/reference to a const
object. shared_future
has a copy constructor, and it takes the reference by const
. As such, the copy constructor of a shared_future
is thread-safe relative to the shared_future
it is being copied from, so long as all of the other operations on that shared_future
are also thread-safe.
So as long as you don't do anything thread-unsafe to a shared_future
instance, you can make a local copy of that instance from any thread.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.