liveBook · Manning

Chapter 9: Chapter 9. Advanced thread management

What you will learn in chapter 9 of C++ Concurrency in Action, Second Edition

The introduction motivates automatic management of threads and tasks, explains why threads sometimes need to stop early, and previews the chapter’s two topics.

After this chapter you will be able to

What it builds on

Section by section

Introduction

The introduction motivates automatic management of threads and tasks, explains why threads sometimes need to stop early, and previews the chapter’s two topics.

Key terms: std::thread, thread pools, tasks, standard library algorithm, interrupting threads, Please stop request

9.1 Thread pools

This section introduces thread pools as a way to reuse a limited set of threads for concurrent tasks and previews the design questions involved in building one.

Key terms: thread pool, worker threads, queue of pending work, how many threads, allocate tasks to threads, wait for a task to complete

9.1.1 The simplest possible thread pool

This section builds a minimal fixed-size thread pool and explains how it runs tasks, shuts down safely, and where its limitations lie.

Key terms: worker threads, std::thread::hardware_concurrency(), thread-safe queue, submit(), std::function<void()>, std::this_thread::yield(), done flag, join_threads, try-catch block, worker_queue

9.1.2 Waiting for tasks submitted to a thread pool

The section makes thread-pool tasks waitable and result-bearing, then shows how to use them effectively in parallel_accumulate.

Key terms: submit(), std::future<>, task handle, std::result_of<>, std::packaged_task<>, std::move(), function_wrapper, std::function<>, parallel_accumulate, num_blocks

9.1.3 Tasks that wait for other tasks

This section shows why recursive tasks can deadlock in a fixed-size thread pool and how running queued work while waiting makes a pool-based Quicksort possible.

Key terms: thread pool, tasks that wait for other tasks, deadlock, Quicksort, run_pending_task(), worker_thread(), do_sort(), thread_pool, submit(), queue

9.1.4 Avoiding contention on the work queue

This section reduces contention in a thread pool by giving workers local work queues, then explains why uneven workloads still require work stealing.

Key terms: shared work queue, contention, cache ping-pong, lock-free queue, thread_local, std::unique_ptr<>, std::queue, submit(), run_pending_task(), worker_thread()

9.1.5 Work stealing

The section shows how a thread pool can let idle workers steal tasks from other workers’ queues using a simple, mutex-protected design.

Key terms: work_stealing_queue, std::deque<function_wrapper>, push(), try_pop(), try_steal(), mutex, last-in-first-out, cache, Quicksort, run_pending_task()

9.2 Interrupting threads

The section introduces cooperative thread interruption as a reusable way to ask a long-running thread to stop gracefully.

Key terms: interrupting threads, signal, terminate nicely, common mechanism, C++11 Standard, interface for launching and interrupting a thread

9.2.1 Launching and interrupting another thread

The section sketches an interruptible thread interface and shows how its constructor gives the launching thread access to the new thread’s interruption flag.

Key terms: interruptible_thread, std::thread, interrupt(), interruption_point(), thread_local, this_thread_interrupt_flag, promise, future, flag, lambda

9.2.2 Detecting that a thread has been interrupted

The section shows how a thread detects an interruption at a safe point and why that approach is insufficient while the thread is blocked.

Key terms: interruption flag, interruption_point(), thread_interrupted, blocked waiting, interruptible

9.2.3 Interrupting a condition variable wait

The section shows why notifying a condition variable is not enough to interrupt its wait reliably, then uses short timed waits to bound how long an interruption can go unnoticed.

Key terms: interruptible_wait(), interruption_point(), interrupt_flag, std::condition_variable, spurious wake-ups, race condition, wait(), set_condition_variable(), mutex, deadlock

9.2.4 Interrupting a wait on std::condition_variable_any

The section shows how a custom lock makes waits on std::condition_variable_any interruptible without a race between registering the wait and entering it.

Key terms: std::condition_variable_any, std::condition_variable, std::unique_lock<std::mutex>, custom lock type, set_clear_mutex, thread_cond_any, Lockable, custom_lock, interrupt flag, spurious wake

9.2.5 Interrupting other blocking calls

For blocking calls such as future waits that cannot be interrupted directly, this section uses short timed waits to check for interruption and explains the latency–overhead tradeoff.

Key terms: interruptible_wait(), std::future<>, wait_for, interrupt flag, 1 ms, high-resolution clock, clock tick, task-switching overhead

9.2.6 Handling interruptions

This section explains how an interrupted thread can handle a thread_interrupted exception, continue working, or terminate safely without ending the program.

Key terms: thread_interrupted, catch block, interrupt(), interruption point, exception-safety precautions, resources, coherent state, std::terminate(), std::thread, interruptible_thread

9.2.7 Interrupting background tasks on application exit

The section shows how to shut down long-running background tasks by interrupting them, then joining them after all have been asked to stop.

Key terms: background threads, interrupt, join, interruption_point(), interruption point, destructor calls, exception-handling code

9.3 Summary

The chapter summary recaps how thread-pool scheduling can improve throughput and avoid deadlock, and how interruption points can let one thread stop another’s work.

Where this is used later

Concepts explained in this chapter

← Chapter 8: Chapter 8. Designing concurrent code Chapter 10: Chapter 10. Parallel algorithms →

These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.