Ch 33: 原子类型 - AtomicBool/Int/Ptr
原子类型提供了在多线程环境下进行无锁并发编程的能力。Rust标准库提供了多种原子类型,它们保证操作的原子性,即不会被中断。
2. 常用原子类型
Section titled “2. 常用原子类型”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);}可用原子类型:
AtomicBoolAtomicI8,AtomicI16,AtomicI32,AtomicI64,AtomicIsizeAtomicU8,AtomicU16,AtomicU32,AtomicU64,AtomicUsizeAtomicPtr<T>
3. 基本操作
Section titled “3. 基本操作”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));}4. compare_exchange - CAS操作
Section titled “4. compare_exchange - CAS操作”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));}5. Ordering - 内存顺序
Section titled “5. Ordering - 内存顺序”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:计数器等不需要顺序保证的场景
6. fetch_update - 便捷方法
Section titled “6. fetch_update - 便捷方法”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));}7. 与普通类型的转换
Section titled “7. 与普通类型的转换”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);}8. 实现无锁计数器
Section titled “8. 实现无锁计数器”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));}9. 实现无锁链表(简化版)
Section titled “9. 实现无锁链表(简化版)”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!("无锁链表插入成功");}10. 注意事项
Section titled “10. 注意事项”- 选择合适的Ordering:越强的Ordering性能越低
- Relaxed的陷阱:只保证原子性,不保证顺序
- compare_exchange vs compare_exchange_weak:weak可能在没有变化时失败,但性能更好
- 边界检查:原子操作不能替代锁用于复杂数据结构
- 64位平台:AtomicI64/AtomicU64在32位平台可能不支持
11. 总结
Section titled “11. 总结”原子类型核心API:
new(val)- 创建原子值load(Ordering)- 读取store(val, Ordering)- 写入fetch_add/sub(val, Ordering)- 原子加减compare_exchange(expected, new, success, failure)- CAS操作swap(val, Ordering)- 交换
原子类型是构建高效并发数据结构的基础,适用于:
- 计数器、标志位
- 无锁数据结构
- 线程间简单通信