多线程编程进阶
需要预先学习: 多线程编程基础 数据共享问题与锁 线程间通信的问题 锁解决了"互斥"(同一时刻只有一个线程进临界区),但没解决"等待":线程 A 要等线程 B 完成某件事(比如数据准备好了)才能继续,A 应该怎么等? 忙等:while (!ready) {} 死循环空转,浪费 CPU,还带来数据竞争 轮询:while (!ready) { sleep(1ms); } 浪费少些,但有延迟,且 ready 的读写仍要同步 这两种方案都不优雅。标准答案有两个:条件变量(等待"事件")和 future/promise(等待"结果")。本篇文章围绕它们展开,最后实现一个线程池。 条件变量 std::condition_variable 条件变量(condition variable)让线程阻塞等待某个条件成立,由其他线程唤醒它。它必须配合 std::unique_lock(和一把互斥量)使用。 核心 API: 函数 行为 wait(lock) 阻塞,并自动解锁;被唤醒后...
原子操作
需要预先学习: 多线程编程基础 数据共享问题与锁 为什么要原子操作 回顾《数据共享问题与锁》中的计数器例子:两个线程各执行 100 万次 ++counter,结果不是 200 万。原因是 ++counter 在底层是"读 → 加 → 写"三步,两个线程的三步交错执行,更新互相覆盖。 用互斥锁可以解决,但代价不小:lock() 通常涉及系统调用(竞争时线程睡眠/唤醒)、缓存行失效、上下文切换。如果只是"把一个变量加 1"这种简单操作,锁是杀鸡用牛刀。 原子操作(atomic operation)就是答案:不可分割的操作——要么完整执行,要么完全不执行,中间不可能被其他线程插入。x = 1 这类单条机器指令天然是原子的;而"读-改-写"这类多步操作,需要硬件提供特殊指令(如 x86 的 lock 前缀指令)保证原子性。 std::atomic<T> 把这种能力封装成标准库类型。用它改写计数器: #include <atomic> #include <iostream> #incl...


