MST

星途 面试题库

面试题:Rust中loop表达式构建的无限循环与线程安全

假设你正在编写一个多线程Rust程序,其中一个线程使用loop表达式构建了一个无限循环来不断处理任务。为了保证线程安全,你需要采取哪些措施?请详细说明,并给出相关代码示例,包括如何使用锁机制(如Mutex)来避免数据竞争。
29.9万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. 线程安全措施
    • 共享数据保护:使用锁机制(如Mutex)来保护共享数据,防止多个线程同时访问和修改,从而避免数据竞争。
    • 消息传递:使用通道(channel)在不同线程间安全地传递数据,而不是直接共享数据。这是Rust基于“所有权”和“借用”原则的并发编程的重要方式。
  2. 使用Mutex避免数据竞争示例
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // 使用Arc来共享数据的所有权,Mutex用于保护数据
    let shared_data = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            // 加锁获取对数据的可变引用
            let mut num = data.lock().unwrap();
            *num += 1;
            println!("Thread incremented data to: {}", *num);
        });
        handles.push(handle);
    }

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

    println!("Final data value: {}", *shared_data.lock().unwrap());
}

在上述代码中:

  • Arc<Mutex<T>>用于在多个线程间安全地共享数据TArc(原子引用计数)允许在多个线程间共享数据的所有权,Mutex提供了互斥访问,确保同一时间只有一个线程可以访问数据。
  • 在每个线程中,通过data.lock().unwrap()获取锁,如果获取成功(unwrap在这里假设获取锁不会失败),则可以安全地修改共享数据。
  • 主线程等待所有子线程完成,最后打印出共享数据的最终值。
  1. 使用通道示例
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let mut handles = vec![];

    for _ in 0..10 {
        let tx_clone = tx.clone();
        let handle = thread::spawn(move || {
            // 发送数据到通道
            tx_clone.send(1).unwrap();
        });
        handles.push(handle);
    }

    let mut sum = 0;
    for _ in 0..10 {
        // 从通道接收数据
        sum += rx.recv().unwrap();
    }

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

    println!("Sum of received data: {}", sum);
}

在这个示例中:

  • mpsc::channel()创建了一个多生产者单消费者通道。
  • 每个线程使用tx.send()将数据发送到通道,主线程使用rx.recv()从通道接收数据。这种方式通过消息传递避免了共享数据带来的数据竞争问题。