MST

星途 面试题库

面试题:Rust中UnsafeCell与并发安全

假设你正在编写一个多线程环境下使用UnsafeCell的程序,为了保证线程安全,你需要采取哪些措施?请详细阐述并给出代码示例,同时说明如何避免数据竞争。
40.4万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. 措施阐述
    • 使用互斥锁(Mutex):在访问UnsafeCell内部数据时,通过互斥锁来确保同一时间只有一个线程可以访问。互斥锁会阻止其他线程进入临界区,从而避免数据竞争。
    • 使用原子操作:对于简单的数据类型,如整数等,可以使用原子操作。原子操作在硬件层面保证了操作的原子性,即不可分割性,不会被其他线程打断,避免数据竞争。
  2. 代码示例(以Rust语言为例)
use std::cell::UnsafeCell;
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let shared_data = Arc::new(Mutex::new(UnsafeCell::new(0)));
    let mut handles = vec![];

    for _ in 0..10 {
        let data = shared_data.clone();
        let handle = thread::spawn(move || {
            let mut data_ref = unsafe { &mut *data.lock().unwrap().get() };
            *data_ref += 1;
        });
        handles.push(handle);
    }

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

    let result = unsafe { *shared_data.lock().unwrap().get() };
    println!("Final result: {}", result);
}

在上述代码中:

  • Arc用于在多个线程间共享数据,Mutex用于保证同一时间只有一个线程能访问UnsafeCell
  • 通过lock方法获取锁,进入临界区,访问UnsafeCell内部数据并修改。
  1. 避免数据竞争
    • 使用同步原语:如上述代码使用Mutex,它通过加锁和解锁机制,使得只有持有锁的线程能访问共享数据,其他线程等待锁的释放,从而避免多个线程同时修改共享数据导致的数据竞争。
    • 遵循内存模型规则:在多线程编程中,要遵循所在编程语言的内存模型规则。例如在Rust中,通过所有权系统和类型系统来辅助避免数据竞争。在使用UnsafeCell时,通过unsafe块来明确告知编译器程序员知道自己在做可能不安全的操作,同时结合同步原语确保操作的安全性。