面试题答案
一键面试use std::sync::atomic::{AtomicU64, Ordering};
use std::thread;
fn main() {
let num_threads = 10;
let shared_value = AtomicU64::new(1);
let mut handles = Vec::with_capacity(num_threads);
for _ in 0..num_threads {
let shared_value_clone = shared_value.clone();
let handle = thread::spawn(move || {
loop {
let current = shared_value_clone.load(Ordering::SeqCst);
let new_value = current * current;
if shared_value_clone.compare_and_swap(current, new_value, Ordering::SeqCst) == current {
break;
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final value: {}", shared_value.load(Ordering::SeqCst));
}
Ordering
参数的作用
SeqCst
(顺序一致性):- 在这个场景中使用
SeqCst
,保证了所有线程对AtomicU64
变量的操作顺序是一致的。也就是说,所有线程都能以相同的顺序观察到对这个变量的修改。 - 虽然
SeqCst
是最严格的内存序,它会带来一定的性能开销,但能确保所有线程看到的内存状态变化是一致的,适合在对数据一致性要求极高的场景中使用。
- 在这个场景中使用
- 其他可能的
Ordering
:Acquire
和Release
:Acquire
内存序保证了从内存加载数据时,在此之前的所有读操作都已完成。Release
内存序保证了在此之后的所有写操作都已完成。如果使用Acquire
和Release
内存序来替代SeqCst
,在这个场景中可能会导致一些线程看到不一致的操作顺序,因为它们不如SeqCst
严格。Relaxed
:Relaxed
内存序是最宽松的,它只保证原子操作本身的原子性,不保证任何内存顺序。在这个场景中如果使用Relaxed
,可能会出现线程读取到旧值或者写入的值没有及时被其他线程看到的情况,无法满足需求。
通过使用合适的Ordering
,特别是SeqCst
,在这个多线程操作AtomicU64
变量的场景中,能够有效地处理竞争条件,保证数据的一致性。