1. Problem It Solves
Starting work and transporting its eventual result are separate concerns. std::thread runs an explicit callable, std::async couples task launch to a future, and a promise/future pair creates a one-result communication channel.
Focus on the smallest useful form, its observable behavior, and its safety boundary.
2. Prerequisites
Days 7 and 21-23: threads, synchronization, RAII, exceptions, return values, and ownership.
3. Core Idea
A future is the receiving end of shared asynchronous state. A promise writes that state manually; async owns the producer mechanics and returns the receiving future directly.
Identify the objects and types, today's operation, and the printed result. This connects syntax to behavior.
4. Minimal Syntax
std::promise<int> promise;
auto result = promise.get_future();
std::thread producer([&] { promise.set_value(21); });
auto task = std::async(std::launch::async, [] { return 42; });5. How It Works
The promise exposes its future before a producer thread is started.
One thread stores 21 in the promise state, while
std::asyncruns a separate function that returns 42.Calling
getwaits if necessary, transfers each result or exception once, and prints deterministic values.
6. Common Mistakes
Destroying a joinable
std::threadcallsstd::terminate; callinggettwice on the same future is also invalid.Do not copy the pattern without checking launch policy, thread join, promise fulfillment, broken promises, exception transport, and one-time future consumption. A program may compile while still having the wrong lifetime, ownership, invalidation, ordering, or performance behavior.
7. When to Use It
Use it when work can overlap and the caller needs a typed eventual result or exception.
Avoid it when the task is tiny, strictly ordered, or a direct function call is clearer and cheaper.
8. Simple Example
A manual producer sends 21 through a promise, while an async task computes 42. Main receives both through futures and joins the explicit thread.
The .cpp file uses fixed data. Predict its output, compile it, then change one value and test the prediction.
Complete sample code
Source file
cpp14/41_thread_async_future_promise/main.cpp
#include <future>
#include <iostream>
#include <thread>
int main() {
std::promise<int> promise;
std::future<int> promised = promise.get_future();
std::thread producer([&promise] {
promise.set_value(21);
});
auto asynchronous = std::async(std::launch::async, [] {
return 42;
});
std::cout << "promise: " << promised.get() << "\n";
std::cout << "async: " << asynchronous.get() << "\n";
producer.join();
}
9. Key Takeaways
Threads execute callables; futures transport completion, values, and exceptions.
A future is the receiving end of shared asynchronous state. A promise writes that state manually;
asyncowns the producer mechanics and returns the receiving future directly.The compiler or library follows a precise rule; verify launch policy, thread join, promise fulfillment, broken promises, exception transport, and one-time future consumption.
Prefer the smallest form that communicates intent and measure costs when performance matters.
10. Self-Check Questions
Easy — What is the main purpose of std::thread, std::async, future, and promise?
Medium — What makes
future.get()wait until its producer has supplied a value?Hard — How does an exception thrown inside an
std::asynctask reach the thread that callsget?