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. 高并发用 线程池
相关推荐
Wang's Blog3 小时前
Java 项目实战:交友项目 - 联系人列表
java·开发语言·交友
傲世仙尊3 小时前
继承-类设计层次复用切片转换与菱形继承的死结
c++
我命由我123453 小时前
访客系统形式(有用户概念、无用户概念)
java·开发语言·前端·javascript·python·产品运营·产品经理
架构师伯子明3 小时前
FFmpeg C++学习(一):编译和demo
开发语言·c++·学习
纪念 2294 小时前
C++算法(六)
开发语言·c++·算法
香蕉大香蕉(06敬畏市场)4 小时前
MySQL 单点详解(01)
java·数据库·mysql·面试·博客·实习
ShineWinsu4 小时前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
LaughingZhu4 小时前
Product Hunt 热榜 2026-10-30:Empacer、Scape、Floot in ChatGPT
java·前端·数据库·人工智能·chatgpt·notion
niucloud-admin4 小时前
NIUCLOUD PHP SAAS上门家政使用文档:服务保障
java·开发语言·php
AI的探索之旅5 小时前
97 个 OpenCV 实例(三十七):二维码识别,一张图四个码的陷阱
c++·opencv·计算机视觉