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. 高并发用 线程池
相关推荐
Anastasiozzzz1 小时前
从有限状态机到智能体图:传统 FSM 与 Agent Graph的演进
java·人工智能·python·ai
fqbqrr6 小时前
2606C++,C++构的多态
开发语言·c++
小欣加油7 小时前
leetcode56 合并区间
c++·算法·leetcode·职场和发展
wang09077 小时前
自己动手写一个spring之IOC_2
java·后端·spring
来杯@Java7 小时前
学生选课管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·maven·mybatis
Yolo_TvT8 小时前
C++:析构函数
c++
不知名的老吴8 小时前
线程的生命周期之线程“插队“
java·开发语言·python
ANnianStriver9 小时前
PetLumina-02-后端开发与前后端联调
java·ai·sa-token
Hello:CodeWorld9 小时前
C 风格变参 vs C++ 变参模板:核心区别与选型指南
c语言·c++·算法