C++ 多线程与并发

这是现代 C++ 进阶最硬核、最值钱 的知识点,我用清晰、实战、不晦涩的方式给你讲透,学完就能写高并发代码。


一、先搞懂:为什么要用多线程?

  1. 同时干多件事(后台下载 + 界面操作)
  2. 利用多核 CPU,提升程序速度
  3. 避免阻塞(一个卡住不影响整体)

代价:线程安全、数据竞争、死锁 ------ 必须学会控制。


二、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++ 并发最佳实践(黄金法则)

  1. 优先用 atomic,不加锁,性能最高
  2. 必须加锁时,用 lock_guard/unique_lock
  3. 少用 detach (),尽量用 join ()
  4. 共享变量必须保护
  5. 复杂同步用 条件变量
  6. 高并发用 线程池
相关推荐
库玛西5 小时前
哈夫曼树与前缀编码:数据压缩的贪心核心
c语言·c++·笔记·考研
别动我齐刘海5 小时前
ROS2 Jazzy + C++ 实战路线——进阶学习3
c++·人工智能·vscode·python·算法·机器学习·机器人
Bs_MoneyMagnet5 小时前
基于springboot+vue的非遗物质文化遗产系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
万物智能5 小时前
波形发生AD9833模块配置—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
java
0+1115 小时前
算法 --滑动窗口
c++·算法·leetcode
计算机毕设定制辅导-无忧学长5 小时前
《基于SpringBoot的未成年人健康知识科普平台的设计与实现》
java·开发语言·vue.js·spring boot·未成年人健康知识科普平台
Wang's Blog5 小时前
Java 项目实战: 外卖平台-数据库环境搭建与十一张表结构解析
java·服务器·redis
stolentime5 小时前
(有原题)CSP-S2026第一轮试题(附答案解析、markdown源码)
c++·csp
m0_734571765 小时前
深入理解C++ RAII
开发语言·c++
白远山6 小时前
上海24小时自助健身房系统软件开发实战指南
java·架构·uni-app·需求分析