现代 C++ 实战(12):多线程基础
第一季讲完语言特性,第二季进入并发与工程。第一课是 C++11 起就有的四件套:std::thread、mutex、condition_variable、atomic——创建并行任务、保护共享数据、线程间等待通知、无锁计数。
这一篇对应 demo:ref/cpp_demo/concurrency/thread_demos/(含 thread 基础、mutex、条件变量、atomic、线程安全队列)。
这是「现代 C++ 实战」系列的第 12 篇,第二季开篇。建议先读 第 11 篇:Concepts。
一、为什么需要多线程?
- 利用多核:CPU 密集型任务拆到多个核并行
- 重叠 I/O 与计算:一个线程等磁盘/网络,另一个继续算
- 响应性:UI 线程不阻塞于后台任务
C++ 标准库从 C++11 起提供跨平台线程抽象,不必直接写 pthread(Linux)或 Win32 API。
二、std::thread:创建、join、detach
1 |
|
| 操作 | 含义 |
|---|---|
join() |
阻塞直到线程函数返回 |
detach() |
分离,线程独立运行;不可再 join |
| 析构 | 若既未 join 也未 detach → std::terminate |
传参注意:默认按值拷贝;传引用用 std::ref(x);移动大对象用 std::move。
1 | std::thread t(worker, std::ref(shared_data)); |
三、数据竞争与 std::mutex
多线程同时读写同一变量且至少一个是写 → 数据竞争(data race) → 未定义行为。
1 |
|
互斥锁 std::mutex:同一时刻只有一个线程持有锁。
四、RAII 锁:lock_guard 与 unique_lock
| 类型 | 特点 |
|---|---|
lock_guard |
构造加锁、析构解锁;简单场景 |
unique_lock |
可 defer_lock、try_lock、配合 condition_variable |
1 | { |
永远用 RAII 管理锁——不要手写 lock() / unlock() 配对,异常路径容易漏解锁。
五、condition_variable:生产者-消费者
线程需要等待某个条件(队列非空、任务完成),而不是忙等(burn CPU):
1 |
|
标准模式:wait(lock, predicate) 防止虚假唤醒;修改共享状态时在锁内,通知在锁外亦可。
demo:thread_condition_variable.cpp、thread_safe_queue.cpp。
六、std::atomic:无锁计数器
简单整型增减,可用原子操作避免锁:
1 |
|
| mutex | atomic | |
|---|---|---|
| 适用 | 保护复杂临界区、多变量不变式 | 单个整型/指针的简单操作 |
| 开销 | 可能系统调用 | 通常 CPU 原子指令 |
| 误用 | 死锁 | 只保护一个变量,复合操作仍需 care |
memory_order(relaxed / acquire / release)进阶见 C++ 内存模型;默认 seq_cst 最安全。
七、常见并发 Bug
| 问题 | 表现 | 缓解 |
|---|---|---|
| 数据竞争 | 结果随机、崩溃 | mutex / atomic |
| 死锁 | 两线程互相等锁 | 固定加锁顺序、try_lock、超时 |
| 忘记 join | terminate | join 或 detach;C++20 jthread 自动 join(第 13 篇) |
| 伪共享 | 多核缓存行抖动 | 对齐、padding(高性能场景) |
八、demo 导览
ref/cpp_demo/concurrency/thread_demos/ 通常包含:
| 文件 | 主题 |
|---|---|
thread_demo.cpp |
thread 创建与 join |
thread_sync.cpp |
mutex 与数据竞争对比 |
thread_condition_variable.cpp |
条件变量 |
thread_atomic.cpp |
atomic vs mutex |
thread_safe_queue.cpp |
线程安全队列 |
1 | cd ref/cpp_demo/concurrency/thread_demos |
链接时需 -pthread(Linux)或 CMake find_package(Threads)。
九、小结
| 组件 | 用途 |
|---|---|
std::thread |
启动并行任务,join/detach |
mutex + RAII 锁 |
互斥访问共享数据 |
condition_variable |
等待条件、生产者-消费者 |
atomic |
无锁简单计数/标志 |
现代 C++ 实战系列第 12 篇完。下一篇 C++20 同步原语——jthread、semaphore、latch、barrier。
系列导航
| 篇号 | 标题 | 状态 |
|---|---|---|
| 11 | Concepts 与模板进阶 | ✅ |
| 12 | 多线程基础(本篇) | ✅ |
| 13 | C++20 同步原语 | 下一篇 |
完整大纲见工作区 docs/CPP_SERIES_OUTLINE.md。










