In C++11 and beyond, parallelism and asynchronous programming became a first‑class citizen of the language. The standard library provides two key abstractions for launching tasks asynchronously: std::async and std::future. These tools simplify the management of background operations, allow you to avoid blocking the main thread, and provide a clean mechanism to retrieve results or propagate exceptions. Below we explore how they work, common pitfalls, and best practices.
1. What is std::async?
std::async launches a function (or a callable object) potentially in a new thread and returns a std::future representing the eventual result. The function signature is:
template <class F, class... Args>
std::future<std::invoke_result_t<F, Args...>>
async(std::launch policy, F&& f, Args&&... args);
The policy parameter controls when the task executes:
std::launch::async– guarantees a new thread will be started.std::launch::deferred– execution is postponed until thefutureis accessed.std::launch::async | std::launch::deferred– default, the implementation decides.
If you omit the policy, the default is the bitwise OR of both options.
2. Retrieving Results with std::future
A `std::future
` can be queried in two ways: – `future.get()` – blocks until the value is ready and returns it (or throws if the task threw an exception). – `future.wait()` or `future.wait_for()` – block only until the result is ready or a timeout occurs, returning a status. Once a `future` has been retrieved (via `get()`), it becomes invalid; calling `get()` again will result in `std::future_error`. ### 3. Example: Parallel Fibonacci “`cpp #include #include #include #include // Expensive recursive Fibonacci int fib(int n) { if (n fut1 = std::async(std::launch::async, fib, 20); std::future fut2 = std::async(std::launch::async, fib, 21); std::cout `). For timeouts, combine `wait_for` with a cancellation token: “`cpp if (fut.wait_for(std::chrono::seconds(1)) == std::future_status::ready) { std::cout