并发的硬件基础

原理

多线程并发在硬件层面由以下机制支撑:

缓存一致性协议(MESI):多核 CPU 通过总线嗅探维护 L1/L2 缓存一致性。Modified → Exclusive → Shared → Invalid 状态机确保所有核心看到一致的内存视图。

内存序(Memory Order):CPU 和编译器可能重排指令。x86 提供较强保证(Load-Load, Load-Store, Store-Store 不重排),Store-Load 可能重排。ARM 提供较弱保证——需要显式屏障。

原子操作:在 x86 上 LOCK 前缀锁住内存总线或缓存行,实现原子 RMW(read-modify-write)。std::sync::atomic 暴露了 Ordering::Relaxed/Acquire/Release/AcqRel/SeqCst

Mutex 实现std::sync::Mutex 底层用 futex(Linux)或 SRWLOCK(Windows)——先自旋锁(spinlock)尝试几次,失败则陷入内核等待。自旋锁适合临界区极短的场景。

Rust 的 Send / Sync trait 在编译期阻止数据竞争:Send = 可安全转移所有权到另一线程;Sync = 可安全地从另一线程通过引用访问。


语法

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicI32, Ordering};
 
// 基础线程
let handle = thread::spawn(|| { println!("worker"); });
handle.join().unwrap();
 
// Arc + Mutex — 多线程共享可变状态
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
    let c = Arc::clone(&counter);
    handles.push(thread::spawn(move || {
        let mut n = c.lock().unwrap();
        *n += 1;
    }));
}
for h in handles { h.join().unwrap(); }
 
// 原子类型
let a = AtomicI32::new(0);
a.fetch_add(1, Ordering::SeqCst);
 
// mpsc 通道
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || { tx.send(42).unwrap(); });
assert_eq!(rx.recv().unwrap(), 42);

内存序层级

Ordering保证性能
Relaxed原子性,重排随意最快
Acquire/Release成对同步,单方向屏障中等
AcqRel双向屏障
SeqCst全局顺序一致性最慢

实践

力扣问题

力扣: 力扣线段树 — 单线程适用

AI 自检

  1. x86 的 TSO(Total Store Order)内存模型与 ARM 的弱内存模型的区别?
  2. Mutex<T>RwLock<T> 的性能差异?读多写少的场景如何选择?