这是现代 C++ 进阶最硬核、最值钱 的知识点,我用清晰、实战、不晦涩的方式给你讲透,学完就能写高并发代码。
一、先搞懂:为什么要用多线程?
- 同时干多件事(后台下载 + 界面操作)
- 利用多核 CPU,提升程序速度
- 避免阻塞(一个卡住不影响整体)
代价:线程安全、数据竞争、死锁 ------ 必须学会控制。
二、C++ 多线程核心 5 大组件(必须背)
C++11 之后自带线程库 <thread>,跨平台,不用再写 pthread。
1. std::thread ------ 创建线程
cpp
运行
#include <iostream>
#include <thread>
using namespace std;
void func() {
cout << "子线程运行\n";
}
int main() {
thread t(func); // 创建并启动线程
t.join(); // 等待线程结束(必须写!)
return 0;
}
两个关键函数
join():主线程等待子线程完成detach():分离线程,后台运行(谨慎使用,容易出坑)
2. std::mutex ------ 互斥锁(解决数据竞争)
多线程同时修改同一个变量 = 数据混乱 = 崩溃必须用锁保护。
cpp
运行
#include <mutex>
mutex mtx;
int cnt = 0;
void add() {
for (int i = 0; i < 100000; ++i) {
mtx.lock(); // 加锁
cnt++; // 安全修改
mtx.unlock(); // 解锁
}
}
3. lock_guard /unique_lock ------ 自动锁(RAII)
手动 lock/unlock 极易忘写,导致死锁! 现代 C++ 一律用自动锁。
cpp
运行
void add() {
mtx.lock(); // 不推荐
...
mtx.unlock();
// 推荐写法
lock_guard<mutex> lock(mtx); // 构造加锁,析构自动解锁
}
unique_lock 更强大:
- 可以临时解锁
- 可以延迟加锁
- 配合条件变量使用
4. std::condition_variable ------ 条件变量(线程同步)
用于:生产者 - 消费者模型一个线程等通知,另一个线程发通知。
cpp
运行
condition_variable cv;
mutex mtx;
bool ready = false;
void consumer() {
unique_lock<mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待信号
cout << "开始消费\n";
}
void producer() {
{
lock_guard<mutex> lock(mtx);
ready = true;
}
cv.notify_one(); // 唤醒一个等待线程
}
5. std::atomic ------ 原子变量(无锁并发)
对简单变量(int/bool)操作,不加锁也能线程安全,性能极高。
cpp
运行
#include <atomic>
atomic<int> cnt = 0;
void add() {
for (int i = 0; i < 100000; ++i) {
cnt++; // 原子操作,安全,无锁
}
}
三、多线程必学:生产者 - 消费者模型
这是面试 + 项目最常考模型。
cpp
运行
#include <queue>
queue<int> q;
mutex mtx;
condition_variable cv;
void producer() {
for (int i = 0; i < 10; ++i) {
lock_guard<mutex> lock(mtx);
q.push(i);
cv.notify_one();
}
}
void consumer() {
while (true) {
unique_lock<mutex> lock(mtx);
cv.wait(lock, []{ return !q.empty(); });
int val = q.front();
q.pop();
lock.unlock();
cout << "消费:" << val << endl;
}
}
四、高级并发:async /future(异步任务)
不用手动创建线程,直接获取返回值。
cpp
运行
#include <future>
int func() { return 10; }
int main() {
future<int> f = async(func);
int res = f.get(); // 等待结果
return 0;
}
五、多线程 3 大坑(必须避开)
1. 死锁(Deadlock)
两个线程互相等对方释放锁,程序卡死。避免方法:
- 所有线程按固定顺序加锁
- 尽量用
lock_guard - 不要长时间持有锁
2. 数据竞争
未加锁同时读写变量。避免:锁 or 原子变量
3. 悬空指针 / 引用
线程使用了已销毁的变量。避免:确保生命周期安全。
六、现代 C++ 并发最佳实践(黄金法则)
- 优先用 atomic,不加锁,性能最高
- 必须加锁时,用 lock_guard/unique_lock
- 少用 detach (),尽量用 join ()
- 共享变量必须保护
- 复杂同步用 条件变量
- 高并发用 线程池