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. 高并发用 线程池
相关推荐
AI视觉网奇1 小时前
linux 检索库 判断库是否支持
java·linux·服务器
她的男孩2 小时前
从零搭一个企业后台,为什么我把能力拆成 Starter 和 Plugin
java·后端·架构
RainCity2 小时前
Java Swing 自定义组件库分享(七)
java·笔记·后端
Sam_Deep_Thinking2 小时前
连锁门店的外卖订单平台对接
java·微服务·架构·系统架构
_遥远的救世主_2 小时前
从一次结果集密集型查询 OOM 看 Java 服务的稳定性架构治理
java·后端
一楼的猫2 小时前
从工具链视角对比:番茄作家助手 vs 第三方写作辅助方案
java·服务器·开发语言·前端·学习·chatgpt·ai写作
程序leo源2 小时前
Qt窗口详解
开发语言·数据库·c++·qt·青少年编程·c#
likerhood3 小时前
Java static 关键字从浅入深
java·开发语言
zh_xuan3 小时前
解决VS Code 控制台中文乱码
c++·vscode·乱码