Promises and Multiple Waiting Threads
Single Producer with Multiple Consumers
-
Single producer thread
- Produces a result or an event
-
Multiple consumer threads
- Use the result
- Or wait for the event to occur
-
Used in many applications
std::future and Multiple Waiting Threads
-
Designed for use with a single consumer thread
- Assumes it has exclusive read access to the shared state
-
Cannot be safely shared between threads
- Data race
-
Cannot be copied
- Move only class
std::shared_future
- Can be copied
- Each thread has its own object
- They all share the same state with the
std::promise - Calling
get()orwait()from different copies is safe
Obtaining an std::shared_future object
-
Normally, we do not create a shared future directly
-
We can move from an existing
std::futurestd::shared_future<int> shared_fut1 = std::move(fut);
-
We can call
share()on thestd::futurestd::shared_future<int> shared_fut2 = fut.share();
-
We can also obtain a shared_future directly from a promise
std::shared_future<int> shared_fut3 = prom.get_future();
-
The producer will be the same as before
-
The consumer now takes an
std::shared_futurevoid consume(std::shared_future<int> &fx);
// Example using std::promise and std::future to send a result from a producer
// thread to a consumer thread
#include <functional>
#include <future>
#include <iostream>
#include <thread>
// The producer's task function takes a std::promise as argument
void produce(std::promise<int> &px) {
using namespace std::literals;
// Produce the result
int x = 42;
std::this_thread::sleep_for(2s);
// Store the result in the shared state
std::cout << "Promise sets shared state to " << x << '\n';
px.set_value(x);
}
// The consumer's task function takes an std::future as argument
void consume(std::shared_future<int> &fx) {
// Get the result from the shared state
std::cout << "Future calling get()...\n";
int x = fx.get();
std::cout << "Future returns from calling get()\n";
std::cout << "The answer is " << x << '\n';
}
int main() {
std::promise<int> prom;
std::shared_future<int> shared_fut1 = prom.get_future();
std::shared_future<int> shared_fut2 = shared_fut1;
std::thread thr_consumer(consume, std::ref(shared_fut1));
std::thread thr_consumer2(consume, std::ref(shared_fut2));
std::thread thr_producer(produce, std::ref(prom));
thr_consumer.join();
thr_consumer2.join();
thr_producer.join();
}