MST

星途 面试题库

面试题:Rust中比较交换操作在多线程环境下的应用场景

在Rust的多线程编程中,比较交换操作(CAS)常被用于实现无锁数据结构。请描述一个使用CAS实现多线程安全的计数器的场景,并给出主要的Rust代码片段。
17.2万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

场景描述

在多线程环境下,我们希望实现一个计数器,该计数器能够被多个线程安全地访问和修改,且不需要使用锁机制。使用比较交换操作(CAS)来实现此计数器,线程在尝试更新计数器值时,会先检查当前值是否与预期值相同,如果相同则更新为新值,否则重试。这样可以避免锁带来的性能开销,特别是在高并发场景下,多个线程竞争访问计数器时,CAS操作能够以更高效的方式完成计数器的更新。

主要Rust代码片段

use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

fn main() {
    let counter = AtomicUsize::new(0);

    let mut handles = vec![];
    for _ in 0..10 {
        let counter_clone = counter.clone();
        let handle = thread::spawn(move || {
            for _ in 0..100 {
                loop {
                    let current = counter_clone.load(Ordering::Relaxed);
                    let new = current + 1;
                    if counter_clone.compare_and_swap(current, new, Ordering::Relaxed) == current {
                        break;
                    }
                }
            }
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Final counter value: {}", counter.load(Ordering::Relaxed));
}

在上述代码中:

  1. AtomicUsize 是Rust标准库中提供的原子类型,用于在多线程环境下无锁地操作 usize 类型的数据。
  2. AtomicUsize::new(0) 创建了一个初始值为0的原子计数器。
  3. 在每个线程中,通过 loop 循环不断尝试使用 compare_and_swap 方法更新计数器。compare_and_swap 方法接收当前预期值 current、新值 new 以及内存序 Ordering::Relaxed。如果当前值与预期值相同,则将计数器更新为新值并返回旧值;如果不同,则返回当前实际值,此时线程会重新获取当前值并再次尝试更新。
  4. 最后,主线程等待所有子线程完成,并打印最终的计数器值。