读完这篇,你将掌握:

  1. 线程 vs 进程(厕所 vs 公司)
  2. 为什么 counter++ 会“丢数”?
  3. join vs detach 哪个该用?
  4. 一行 lock_guard 解决数据竞争
  5. std::async 快速实现“线程池”效果

 1. 线程到底是个啥?(1 分钟类比)

概念 类比
进程(Process) 一家公司
线程(Thread) 公司里的员工

所有员工共享公司资源(内存、文件、网络),但可以 同时干不同活


 2. 现实中哪里需要多线程?(你正在用)

场景 主线程 子线程
视频播放器 显示 UI ① 解码视频 ② 下载弹幕 ③ 监听键盘
游戏引擎 渲染画面 ① 物理碰撞 ② 播放音效
服务器 接受连接 每个客户端一个线程
数据分析 显示进度条 并行计算

核心好处

  • 提速(CPU 多核并行)
  • 不卡顿(UI 线程不被阻塞)

 3. C++ 如何创建线程?(3 行代码起步)

cpp

#include <iostream>
#include <thread>
using namespace std;

void work() {
    cout << "子线程:正在搬砖...\n";
}

int main() {
    thread t(work);           // ① 创建线程
    cout << "主线程:我先喝口茶...\n";
    t.join();                 // ② 等待子线程结束
    cout << "主线程:干完了!\n";
}

输出(顺序不定):

text

主线程:我先喝口茶...
子线程:正在搬砖...
主线程:干完了!

t.join() = 主线程排队等子线程 不加 join()?主线程直接退出 → 程序崩溃!


4. 多个线程并行运行(顺序随机!)

cpp

void task(int id) {
    cout << "线程 " << id << " 上线啦!\n";
}

int main() {
    thread t1(task, 1), t2(task, 2), t3(task, 3);
    t1.join(); t2.join(); t3.join();
}

输出示例(每次不同):

text

线程 2 上线啦!
线程 1 上线啦!
线程 3 上线啦!

并行 ≠ 顺序,这就是多线程的魅力(也是坑)

 5. 致命陷阱:共享变量导致“数据竞争”

cpp

int counter = 0;

void add() {
    for (int i = 0; i < 100000; ++i)
        counter++;  // 危险!不是原子操作
}

cpp

thread t1(add), t2(add);
t1.join(); t2.join();
cout << counter << endl;  // 期望 200000,实际常 < 200000 ❌

counter++ 实际是 读 → 加1 → 写,两线程交叉 → 覆盖丢失


6. 一行代码解决:std::lock_guard(推荐!)

cpp

#include <mutex>
mutex mtx;  // 全局一把锁

void add_safe() {
    for (int i = 0; i < 100000; ++i) {
        lock_guard<mutex> lock(mtx);  // 自动 lock + unlock
        counter++;
    } // ← 作用域结束,自动解锁(异常也安全)
}

结果:counter 永远是 200000 ✅

需要详细了解互斥锁的可以->互斥锁


7. 线程常用操作速查表

操作 含义 推荐场景
t.join() 等待线程结束 必须等结果时
t.detach() 后台独立运行 日志、监控等 “火了就跑”
this_thread::sleep_for() 线程睡觉 模拟耗时 / 限流
this_thread::get_id() 获取线程 ID 调试 / 日志

cpp

this_thread::sleep_for(chrono::seconds(2)); // 睡 2 秒
cout << "我的 ID 是: " << this_thread::get_id() << endl;

8. join vs detach:

方法 效果 风险
join() 主线程阻塞等待 安全,但可能卡住
detach() 子线程后台运行 不能再操作 t,否则 undefined behavior

cpp

thread t(task);
t.detach();  // 放飞它,主线程不等
// t.join(); // 报错!已 detach

 9. 线程池雏形:std::async(超简单)

频繁创建线程 = 开销大 → 用 线程池

cpp

#include <future>
#include <iostream>
using namespace std;

int compute(int x) {
    this_thread::sleep_for(chrono::seconds(1));
    return x * 2;
}

int main() {
    auto f1 = async(launch::async, compute, 10);  // 异步执行
    auto f2 = async(launch::async, compute, 20);

    cout << "结果: " << f1.get() + f2.get() << endl;  // 60
}

std::async 自动复用线程,适合 临时并行任务


10. 多线程速查表

概念 说明 必备工具
线程 程序执行最小单位 <thread>
多线程 同时跑多个任务 thread t(func)
数据竞争 共享变量未加锁 counter++
互斥锁 保护共享资源 mutex + lock_guard
join 等待线程结束 t.join()
detach 后台运行 t.detach()
async 异步 + 自动线程池 std::async

行动清单(3 步开启多线程)

  1. 找到并行任务(如下载 + UI)
  2. 用 thread t(func) 创建线程
  3. 共享变量?必须加 lock_guard<mutex>

互斥锁

lock_guard<mutex> lock(mtx);  // 一行搞定安全

 生活类比:公司 vs 员工

公司(进程):有办公室、电脑、打印机 员工(线程)

  • 共享打印机(内存)
  • 同时开会、写代码、接电话
  • 但打印时要排队 → 加锁!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐