线程管理的基础

启动线程

std::thread 可传函数、函数对象、lambda

正确写法

void background_task() { /* ... */ }
std::thread t(background_task);   // 传函数指针,不要加 ()
// 或
std::thread t(&background_task);  // 显式取地址,等价

函数名在表达式中会 衰变为函数指针,正好符合 std::thread 对 callable 的要求。

歧义写法

background_task是类

class background_task { /* ... */ };
std::thread t(background_task());
// 解析为:声明函数 t,参数类型是「指向无参、返回 background_task 的函数的指针」
// t 不是 std::thread 对象!

background_task是函数

void background_task() { /* ... */ }
std::thread t(background_task());
// 解析为:std::thread t( background_task() );
//                      ^^^^^^^^^^^^^^^^^
//                      表达式:调用 background_task(),得到 void

记忆规则:

写法background_task 是类background_task 是函数
t(background_task())声明函数 t(静默坑)先调用函数,再构造(编译失败)
t(background_task)传临时对象(若可默认构造则可行)正确:传函数指针
t((background_task()))构造临时对象再建线程不适用
t{background_task()}构造临时对象再建线程不适用(函数不能 {} 初始化)写法

线程完成

必须遵守的规则

  • 析构前二选一:每个 std::thread 在销毁前必须 join()detach(),否则析构函数调用 std::terminate() 直接终止程序
  • 只能 join 一次:join() 后线程与 std::thread 对象解绑,joinable() 变为 false,再次 join() 是错误
  • join 会阻塞:当前线程一直等到目标线程执行完;第2章指出它不如 condition_variable / future 灵活(超时、轮询等见第4章)

使用场景与对比

方式含义典型场景
join()等待线程结束需要结果、需要保证子线程完成后再继续
detach()不等待,后台运行「发后即忘」;但主线程不能依赖子线程里的局部数据

同步

std::atomic

操作

  • 存储(store)操作,可选用的内存次序有 std::memory_order_relaxed、std::memory_order_release 或 std::memory_order_seq_cst

  • 载入(load)操作,可选用的内存次序有 std::memory_order_relaxed、std::memory_ order_consume、std::memory_order_acquire 或std::memory_order_seq_cst。

  • “读-改-写”(read-modify-write)操作,可选用的内存次序有 std::memory_order_

    relaxed、std::memory_order_consume、std::memory_order_acquire、std::memory_order_release、std::memory_order_acq_rel 或 std::memory_order_seq_cst。

compare_exchange_strong

bool compare_exchange_strong(T& expected, T desire, ...);
  • 成功:原子值原等于 expected → 改为 desired,返回 true
  • 失败:原子值已变 → expected 被更新为 当前值,返回 false(值未改)

failure 的内存序不能是 release/acq_rel(失败时没有「发布」语义)。

strong vs weak

compare_exchange_strongcompare_exchange_weak
失败原因仅当 当前值 ≠ expected同上,还可能 伪失败(spurious failure)
典型用法单次判断、逻辑必须准确放在 while 循环 里重试
性能某些 CPU 上可能多等一轮可能少一次硬 CAS 指令

用法

std::atomic<bool> flag{false};
bool expected = false;
if (flag.compare_exchange_strong(expected, true)) {
    // 抢到:原先确实是 false
} else {
    // 别人已置 true,expected 已被更新为 true
}
/////////  等价 ///////////
bool expected = false;
while (!b.compare_exchange_weak(expected, true) && !expected) {
    // 伪失败或竞争:expected 会被更新,可重试或退出
}

一次性事件

std::future

一次性事件:结果就绪后 不可重置(与条件变量可反复等待不同)

future 是一个模板类,用来等待异步操作的结果。它本身不能直接存值,只能从 promiseasync 那里获取结果

核心方法

方法作用
get()阻塞等待,直到结果就绪,然后返回值(只能调用 1 次)
wait()阻塞等待结果就绪,但不返回值
wait_for(timeout)等待指定时间,超时就返回,不卡死
wait_until(time)等待到指定时间点
valid()判断 future 是否还有效

关键特性

  • get() 只能调用一次,调用后 future 失效
  • 没结果时调用 get()阻塞当前线程,直到结果到来
  • 可以安全接收异步线程抛出的异常(传统线程做不到)

std::promise