Skip to content

Ch 33: 原子类型 - AtomicBool/Int/Ptr

原子类型提供了在多线程环境下进行无锁并发编程的能力。Rust标准库提供了多种原子类型,它们保证操作的原子性,即不会被中断。

use std::sync::atomic;
fn main() {
// 原子布尔
let flag = atomic::AtomicBool::new(false);
flag.store(true, atomic::Ordering::SeqCst);
// 原子整数
let counter = atomic::AtomicI32::new(0);
counter.fetch_add(1, atomic::Ordering::SeqCst);
// 原子指针
let ptr = atomic::AtomicPtr::new(std::ptr::null_mut());
let mut data = Box::new(42i32);
ptr.store(&mut *data as *mut i32, atomic::Ordering::SeqCst);
}

可用原子类型:

  • AtomicBool
  • AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize
  • AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize
  • AtomicPtr<T>
use std::sync::atomic::{AtomicI32, Ordering};
fn main() {
let num = AtomicI32::new(10);
// store - 写入
num.store(20, Ordering::SeqCst);
// load - 读取
let val = num.load(Ordering::SeqCst);
println!("值: {}", val);
// fetch_add - 原子加
let old = num.fetch_add(5, Ordering::SeqCst);
println!("旧值: {}, 新值: {}", old, num.load(Ordering::SeqCst));
// fetch_sub - 原子减
let old = num.fetch_sub(3, Ordering::SeqCst);
println!("旧值: {}, 新值: {}", old, num.load(Ordering::SeqCst));
// swap - 交换
let old = num.swap(100, Ordering::SeqCst);
println!("旧值: {}, 新值: {}", old, num.load(Ordering::SeqCst));
}

Compare-and-swap(CAS)是实现无锁算法的核心:

use std::sync::atomic::{AtomicI32, Ordering};
fn main() {
let num = AtomicI32::new(10);
// compare_exchange - 如果当前值等于期望值,则设置为新值
let result = num.compare_exchange(
10, // 期望值
20, // 新值
Ordering::SeqCst, // 成功时的Ordering
Ordering::SeqCst, // 失败时的Ordering
);
match result {
Ok(old) => println!("替换成功,旧值: {}", old),
Err(_) => println!("替换失败"),
}
// compare_exchange_weak - 较弱版本,可能虚假失败
let mut current = num.load(Ordering::SeqCst);
loop {
let result = num.compare_exchange_weak(
current,
current + 10,
Ordering::SeqCst,
Ordering::SeqCst,
);
match result {
Ok(_) => break,
Err(new_current) => current = new_current,
}
}
println!("最终值: {}", num.load(Ordering::SeqCst));
}
use std::sync::atomic::{AtomicI32, Ordering};
fn main() {
let num = AtomicI32::new(0);
// SeqCst - 顺序一致性(最强,保证所有线程看到相同顺序)
num.store(1, Ordering::SeqCst);
// AcqRel - 获取-释放(用于获取或释放操作)
let old = num.fetch_add(1, Ordering::AcqRel);
// Acquire - 获取(之后的读取看到此操作之前的所有写入)
let val = num.load(Ordering::Acquire);
// Release - 释放(之前的写入对此操作之后的读取可见)
num.store(10, Ordering::Release);
// Relaxed - 宽松(只保证原子性,无顺序保证)
let val = num.load(Ordering::Relaxed);
}

常见场景:

  • SeqCst:需要严格顺序的标志位
  • Acquire:配合Release用于生产者-消费者
  • Relaxed:计数器等不需要顺序保证的场景
use std::sync::atomic::{AtomicI32, Ordering};
fn main() {
let num = AtomicI32::new(10);
// fetch_update: 原子地应用一个函数
num.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
if x < 100 { Some(x * 2) } else { None }
}).unwrap();
println!("值: {}", num.load(Ordering::SeqCst));
}
use std::sync::atomic::{AtomicI32, Ordering};
fn main() {
// 从普通类型创建
let atomic = AtomicI32::new(42);
// 获取内部值(不是原子的)
let val = atomic.into_inner();
println!("内部值: {}", val);
// 使用new创建后加载
let atomic2 = AtomicI32::new(0);
atomic2.store(100, Ordering::SeqCst);
}
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
fn main() {
let counter = AtomicUsize::new(0);
let mut handles = vec![];
for _ in 0..100 {
let counter = &counter;
let handle = thread::spawn(move || {
counter.fetch_add(1, Ordering::Relaxed);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("最终计数: {}", counter.load(Ordering::Relaxed));
}
use std::sync::atomic::{AtomicPtr, Ordering};
use std::ptr;
struct Node {
data: i32,
next: AtomicPtr<Node>,
}
unsafe impl Send for Node {}
unsafe impl Sync for Node {}
fn main() {
let head: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
// 创建一个新节点
let new_node = Box::into_raw(Box::new(Node {
data: 42,
next: AtomicPtr::new(ptr::null_mut()),
}));
// CAS插入头部
let old_head = head.load(Ordering::SeqCst);
unsafe {
(*new_node).next.store(old_head, Ordering::SeqCst);
}
head.store(new_node, Ordering::SeqCst);
println!("无锁链表插入成功");
}
  1. 选择合适的Ordering:越强的Ordering性能越低
  2. Relaxed的陷阱:只保证原子性,不保证顺序
  3. compare_exchange vs compare_exchange_weak:weak可能在没有变化时失败,但性能更好
  4. 边界检查:原子操作不能替代锁用于复杂数据结构
  5. 64位平台:AtomicI64/AtomicU64在32位平台可能不支持

原子类型核心API:

  • new(val) - 创建原子值
  • load(Ordering) - 读取
  • store(val, Ordering) - 写入
  • fetch_add/sub(val, Ordering) - 原子加减
  • compare_exchange(expected, new, success, failure) - CAS操作
  • swap(val, Ordering) - 交换

原子类型是构建高效并发数据结构的基础,适用于:

  • 计数器、标志位
  • 无锁数据结构
  • 线程间简单通信