面试题答案
一键面试原子加载操作在多线程编程里常见的应用场景
- 状态标记:用于标记某个任务或操作是否完成。例如,在多个线程协作完成一项复杂任务时,一个线程完成自己的部分后,通过原子加载操作让其他线程知道任务进度。
- 计数器:多个线程可能需要对一个共享的计数器进行操作,原子加载操作可以保证在读取计数器的值时不会出现数据竞争,例如统计网站的访问量等场景。
- 共享数据访问:当多个线程需要读取共享数据时,原子加载操作可以确保读取到的数据是最新且一致的,避免由于缓存等问题导致的不一致现象。
使用std::sync::atomic::AtomicUsize
进行原子加载操作实现线程间数据共享与同步的示例
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
use std::thread;
fn main() {
let shared_counter = Arc::new(AtomicUsize::new(0));
let mut handles = Vec::new();
for _ in 0..10 {
let counter = Arc::clone(&shared_counter);
let handle = thread::spawn(move || {
// 原子加载操作
let value = counter.load(Ordering::SeqCst);
println!("Thread sees value: {}", value);
// 原子递增操作
counter.fetch_add(1, Ordering::SeqCst);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// 主线程原子加载最终值
let final_value = shared_counter.load(Ordering::SeqCst);
println!("Final value: {}", final_value);
}
在上述代码中,通过Arc<AtomicUsize>
在多个线程间共享一个计数器。每个线程通过load
方法进行原子加载操作获取当前计数器的值,并且通过fetch_add
进行原子递增操作。主线程最后也通过load
获取最终的计数器值。Ordering::SeqCst
代表顺序一致性,是一种较为严格的内存序,确保操作的顺序在所有线程看来都是一致的。不同的应用场景可能会选择不同的内存序,如Relaxed
等更为宽松的内存序,以获得更好的性能,但可能会牺牲一定的数据一致性保障。