Concurrency
Futures and Promises
Transmit values or exceptions asynchronously between producer and consumer threads using std::promise and std::future.
Interview: Unidirectional thread channels, exception propagation across boundaries, and future::get() lifecycle rules.
In C++, std::promise and std::future provide a unidirectional channel to pass values, exceptions, or signals from a producer thread to a consumer thread.
std::promise
The write end of the channel. Used by the producer to set the value or throw an exception.
std::future
The read end of the channel. Used by the consumer to wait for and retrieve the value using get().
Exception Transfer
Allows a background thread to catch an exception and pass it to the main thread using set_exception().
The Single-Use Rule of Futures
A standard std::future is single-use. When you call get(), it blocks until the value is ready, moves the value out of the shared state, and invalidates the future.
Shared Futures
If multiple threads need to query the same asynchronous result, convert the future to a std::shared_future using future::share(). This allows multiple threads to call get() concurrently.
Code Walkthrough
Demonstrates passing values and forwarding runtime exceptions across thread boundaries.
#include <iostream> #include <future> #include <thread> #include <stdexcept>void worker(std::promise<int> promiseObj) { try { // Perform calculations int result = 42; promiseObj.set_value(result); // Pass value to consumer } catch (...) { // Capture exception and pass it to the consumer promiseObj.set_exception(std::current_exception()); } }
int main() { std::promise<int> prom; std::future<int> fut = prom.get_future();
std::thread t(worker, std::move(prom)); // Move promise into thread
try { int val = fut.get(); // Blocks until value is ready std::cout << "Received Value: " << val << std::endl; } catch (const std::exception& e) { std::cerr << "Exception from worker thread: " << e.what() << std::endl; }
t.join(); return 0; }
Interview-Relevant Information
Q: Can you call future::get() multiple times?
Answer: No, calling future::get() on a standard std::future invalidates its internal state. Calling it a second time throws a std::future_error. If you need to read the value multiple times or from multiple threads, use std::shared_future instead.
Q: How do you handle thread exceptions using promises?
Answer: Catch the exception on the worker thread using a try-catch block, capture it using std::current_exception(), and write it to the promise using promise::set_exception(). When the parent thread calls future::get(), the runtime will rethrow the exception there.
Quick Checklist
Did you move the promise into the worker thread? Do you avoid calling get() twice? If yes, your future-promise implementation is correct.
Use Cases
Propagating network responses or database query results from background threads back to the main application thread.
Coordinating startup initialization states between separate subsystem threads.
Common Mistakes
Attempting to copy a std::promise (promises are move-only types and must be moved using std::move).
Calling future::get() on the main thread before starting the thread that fulfills the promise, resulting in a deadlock.