面试题答案
一键面试原子类型在多线程环境下保证数据一致性的原理
在多线程环境中,普通变量的读写操作不是原子性的,这意味着在多个线程同时访问和修改该变量时,可能会出现竞态条件(race condition),导致数据不一致。而原子类型通过硬件指令来保证其操作的原子性,即这些操作不可被中断,要么完整执行,要么不执行。这就避免了多个线程同时对同一数据进行读写时可能出现的数据竞争问题,从而保证了数据一致性。
使用AtomicUsize
实现简单多线程计数器示例
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
fn main() {
// 创建一个原子计数器
let counter = Arc::new(AtomicUsize::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
for _ in 0..1000 {
// 使用fetch_add方法原子性地增加计数器的值
counter.fetch_add(1, Ordering::SeqCst);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// 打印最终的计数器值
println!("Final counter value: {}", counter.load(Ordering::SeqCst));
}
在上述代码中:
Arc<AtomicUsize>
用于在多个线程间共享原子计数器,Arc
(原子引用计数)允许在多个线程间安全地共享数据。AtomicUsize::new(0)
初始化一个值为0的AtomicUsize
类型计数器。fetch_add
方法以原子操作的方式增加计数器的值,Ordering::SeqCst
指定了顺序一致性的内存序,这是最严格的内存序,确保所有线程以相同的顺序观察到所有内存访问。- 多个线程并行地对计数器进行增加操作,最后主线程等待所有线程完成并打印最终的计数器值。