✅ 一、std::thread

已使用 chatgpt 重构笔记结构

C++11 原生线程类

1.1 基本语法

#include <thread>
​
void task(int id) {
    // do something
}
​
int main() {
    std::thread t(task, 42);  // 创建线程执行 task(42)
    t.join();                 // 等待线程结束
}

1.2 支持的任务类型

  • 普通函数

  • lambda 表达式

  • 函数对象(重载 operator())

  • 类成员函数(需要绑定对象)

🧪 示例:绑定成员函数

class Worker {
public:
    void run(int id) {
        std::cout << "Thread " << id << std::endl;
    }
};
​
Worker w;
std::thread t(&Worker::run, &w, 1);  // 注意 &w

1.3 常用函数

函数

作用

join()

等待线程完成,阻塞当前线程

detach()

分离线程,让它后台执行(危险)

joinable()

是否可 join(未 join 或 detach 前)

hardware_concurrency()

返回系统最大并发线程数(只是 hint)

1.4 使用建议

场景

推荐操作

执行任务并等待完成

join() ✅

后台线程(日志/心跳)

detach() ✅ 但需确保资源不被销毁

多核并发

多线程+分工,使用 hardware_concurrency() 做线程池


✅ 二、std::mutex

线程间互斥控制

2.1 基本语法

#include <mutex>
​
std::mutex mtx;
​
void task() {
    mtx.lock();
    // 临界区(访问共享变量)
    mtx.unlock();
}

2.2 推荐用法:RAII 封装

std::lock_guard<std::mutex> lock(mtx);  // 自动上锁和释放(作用域退出即释放)

2.3 支持的类

类名

说明

std::mutex

最基础的互斥锁

std::recursive_mutex

允许同一线程重复加锁

std::timed_mutex

支持超时等待锁

std::shared_mutex(C++17)

支持读写锁(多读/单写)

2.4 使用建议

场景

推荐锁

普通临界区

std::mutex

有递归调用需求

std::recursive_mutex

希望能失败返回

try_lock()

希望支持 timeout

std::timed_mutex

多读少写

std::shared_mutex(需 C++17)


✅ 三、std::atomic<T>

原子操作,无锁同步

3.1 基本语法

#include <atomic>
​
std::atomic<int> counter(0);
​
void add() {
    counter++;
}

所有操作:load()、store()、fetch_add()、compare_exchange_weak/strong() 都是线程安全的无锁操作

3.2 常见操作

操作

示例

含义

x.load()

原子读取

x.store(val)

原子写入

x.fetch_add(1)

原子加

x.fetch_sub(1)

原子减

CAS

x.compare_exchange_weak(expected, newval)

比较并交换

3.3 原子类型支持

  • std::atomic<int/float/bool/...>(POD 类型)

  • std::atomic<T*>(原子指针)

  • std::atomic_flag(最轻量的 spin lock 原语)

  • std::atomicstd::shared_ptr<T>(C++20)

3.4 std::atomic_flag

最小自旋锁示例

std::atomic_flag flag = ATOMIC_FLAG_INIT;
​
void lock() {
    while (flag.test_and_set(std::memory_order_acquire)) {}
}
void unlock() {
    flag.clear(std::memory_order_release);
}

3.5 内存序(默认就是最安全的 seq_cst)

load(memory_order_relaxed)
store(memory_order_release)
fetch_add(memory_order_acq_rel)

3.6 使用建议

场景

建议

原子计数器

std::atomic<int>

标志变量

std::atomic<bool>

自旋锁

std::atomic_flag ✅

多步骤逻辑

用 std::mutex 更安全 ❗


✅ 四、三者何时用谁?

场景

推荐工具

并发执行任务

std::thread ✅

操作共享数据

std::mutex ✅

简单计数 / 状态同步

std::atomic ✅

多线程读、少量写

std::shared_mutex ✅

极致性能 / lock-free

std::atomic + CAS ✅

多步骤逻辑临界区

std::mutex 更清晰 ✅


✅ 五、常见陷阱 ⚠️

错误

原因

忘记 join()

导致主线程退出时子线程被 kill

不用 RAII 解锁

异常或早 return 会忘记 unlock(严重 bug)

用 atomic 实现多步骤逻辑

数据状态可能不一致

用 detach() 却没有同步

很可能访问了悬空对象(UB)

✅ 总结核心口诀:

能用 atomic 就别用锁,能用 lock_guard 就别手动 lock,能用 thread pool 就别乱开线程。