Futures, Tasks, and Thread Pools
In previous chapters, we worked extensively with low-level primitives: thread, mutex, atomic, and condition variable. These give us precise control, but they also impose a significant manual management burden—we have to design synchronization mechanisms ourselves, pass results manually, and handle errors on our own. The C++ standard library provides a set of higher-level asynchronous abstractions to simplify this work: future is a result container, promise is the writing end for a value, packaged_task is a task wrapper, and async is the most convenient way to launch a task. Together, they form the infrastructure for thread pools and task queues.
In this chapter, we start with std::async and std::future to understand the launch strategies for asynchronous tasks and the mechanisms for retrieving results. We then dive into std::promise and std::packaged_task to learn how to manually control value setting and task execution. Finally, we discuss std::shared_future and thread pool design patterns, tying together all the components we have learned so far.