Standard:C++11 introduced std::future, std::promise, and std::async.
using namespace std::chrono_literals;
Watch out: std::async with launch::async returns a future whose destructor blocks until the task completes. Discarding the future (e.g., not capturing the return value) makes the call synchronous. -----------------------------------------------
int compute_sum(int from, int to) { int sum = 0; for (int i = from; i <= to; ++i) sum += i; return sum;}
it after set_exception(), throws std::future_error. Each promise
can deliver exactly one result.
Watch out: calling promise::set_value() more than once, or calling
void producer(std::promise<std::string> promise) { std::this_thread::sleep_for(100ms); // Simulate work promise.set_value("Hello from the producer thread!");}
3. Exception propagation through futures
If the async task throws, the exception is stored
in the future and re-thrown on .get().
int risky_computation(int x) { if (x < 0) { throw std::invalid_argument("Negative input not allowed"); } return x * x;}
4. std::shared_future -- multiple consumers
A regular future can only be .get() once.
shared_future if multiple consumers need the result.
Watch out: calling future::get() more than once is UB. Use
void wait_and_print(std::shared_future<int> sf, std::string name) { int result = sf.get(); // Multiple threads can call .get() std::cout << std::format("{} got result: {}\n", name, result);}int main() { // ---- std::async ---- std::cout << "--- std::async ---\n"; // Launch async tasks (may run in a thread pool) auto future1 = std::async(std::launch::async, compute_sum, 1, 50'000); auto future2 = std::async(std::launch::async, compute_sum, 50'001, 100'000); // Do other work while async tasks run... std::cout << "Computing in background...\n"; // .get() blocks until the result is ready int total = future1.get() + future2.get(); std::cout << std::format("Sum 1..100000 = {}\n", total); // ---- std::promise / std::future ---- std::cout << "\n--- std::promise / std::future ---\n"; std::promise<std::string> promise; std::future<std::string> future = promise.get_future(); // Producer thread sets the value std::thread t(producer, std::move(promise)); // Consumer (main thread) waits for the value std::cout << "Waiting for result...\n"; std::string result = future.get(); // Blocks until value is set std::cout << std::format("Received: {}\n", result); t.join(); // ---- Future status polling ---- std::cout << "\n--- Future Status ---\n"; auto slow_future = std::async(std::launch::async, [] { std::this_thread::sleep_for(200ms); return 42; }); // Check if result is ready without blocking while (slow_future.wait_for(50ms) != std::future_status::ready) { std::cout << "Still waiting...\n"; } std::cout << std::format("Got: {}\n", slow_future.get()); // ---- Exception propagation ---- std::cout << "\n--- Exception Propagation ---\n"; auto bad_future = std::async(std::launch::async, risky_computation, -5); try { int val = bad_future.get(); // Re-throws the exception! std::cout << std::format("Result: {}\n", val); } catch (const std::invalid_argument& e) { std::cout << std::format("Caught from future: {}\n", e.what()); } // ---- shared_future ---- std::cout << "\n--- std::shared_future ---\n"; std::promise<int> shared_promise; std::shared_future<int> sf = shared_promise.get_future().share(); // Multiple consumers waiting on the same result std::thread c1(wait_and_print, sf, "Consumer 1"); std::thread c2(wait_and_print, sf, "Consumer 2"); std::thread c3(wait_and_print, sf, "Consumer 3"); // Produce the result shared_promise.set_value(999); c1.join(); c2.join(); c3.join(); return 0;}