MST

星途 面试题库

面试题:Rust原子加载操作在多线程环境下的应用场景

请描述在Rust中,原子加载操作在多线程编程里常见的应用场景有哪些?并举例说明如何使用`std::sync::atomic::AtomicUsize`进行原子加载操作来实现线程间的数据共享与同步。
12.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

原子加载操作在多线程编程里常见的应用场景

  1. 状态标记:用于标记某个任务或操作是否完成。例如,在多个线程协作完成一项复杂任务时,一个线程完成自己的部分后,通过原子加载操作让其他线程知道任务进度。
  2. 计数器:多个线程可能需要对一个共享的计数器进行操作,原子加载操作可以保证在读取计数器的值时不会出现数据竞争,例如统计网站的访问量等场景。
  3. 共享数据访问:当多个线程需要读取共享数据时,原子加载操作可以确保读取到的数据是最新且一致的,避免由于缓存等问题导致的不一致现象。

使用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等更为宽松的内存序,以获得更好的性能,但可能会牺牲一定的数据一致性保障。