MST
星途 面试题库

面试题:Rust并发控制中的通道与原子操作结合

假设有两个线程,一个线程负责生成一系列数字并通过通道发送,另一个线程接收这些数字,对每个数字进行原子加法操作(使用`AtomicUsize`)。请编写完整的Rust代码实现这个过程,并解释如何确保线程安全以及原子操作在这里的必要性。
30.0万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();
    let atomic_num = Arc::new(AtomicUsize::new(0));

    let atomic_num_clone = atomic_num.clone();
    let producer = thread::spawn(move || {
        for i in 0..10 {
            tx.send(i).unwrap();
        }
    });

    let consumer = thread::spawn(move || {
        for num in rx {
            atomic_num_clone.fetch_add(num, Ordering::SeqCst);
        }
    });

    producer.join().unwrap();
    consumer.join().unwrap();

    println!("Final atomic value: {}", atomic_num.load(Ordering::SeqCst));
}

线程安全的保证

  1. 通道(Channel):通过std::sync::mpsc模块创建的通道,用于线程间安全地传递数据。发送端(tx)和接收端(rx)在不同线程中使用,确保数据传递的线程安全性。
  2. 原子类型(AtomicUsize):使用std::sync::atomic::AtomicUsize来存储共享数据,它提供了原子操作方法,如fetch_add。原子操作保证了在多线程环境下对该值的修改不会发生数据竞争。
  3. Arc(Atomic Reference Counting):使用Arc来共享AtomicUsize实例,Arc是线程安全的引用计数智能指针,允许在多个线程间安全地共享数据。

原子操作的必要性

在多线程环境下,如果使用普通的usize类型进行加法操作,不同线程同时对该值进行读取和修改时,可能会发生数据竞争。原子操作提供了一种无锁的机制,确保在多个线程访问共享资源时,操作是原子的,即要么完全执行,要么完全不执行,避免了数据竞争和不一致的问题。例如,fetch_add方法会原子地将指定的值加到AtomicUsize实例上,并返回旧值,保证了操作的原子性和线程安全性。