MST
星途 面试题库

面试题:Rust借用规则在并发场景下如何避免数据竞争

请阐述Rust借用规则的核心要点,并说明在并发编程中,这些规则是怎样防止数据竞争问题出现的。可以结合简单的代码示例来解释。
14.8万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

Rust借用规则核心要点

  1. 同一作用域内,可变借用只能有一个
    • 这意味着在给定的代码块中,不能同时有多个对同一数据的可变引用。例如:
    let mut num = 5;
    let r1 = &mut num;
    // 下面这行代码会报错,因为已经有了一个可变借用r1
    // let r2 = &mut num; 
    *r1 = 6;
    println!("{}", num);
    
  2. 不可变借用可以有多个,但不能与可变借用同时存在
    • 可以有多个不可变引用同时访问数据,但当有可变引用时,不可变引用就不允许存在。例如:
    let num = 5;
    let r1 = #
    let r2 = #
    println!("{} {}", r1, r2);
    // 下面这行代码会报错,因为已经有不可变借用r1和r2,不能再创建可变借用
    // let r3 = &mut num; 
    
  3. 借用的生命周期必须小于等于被借用对象的生命周期
    • 借用的数据不能在被借用对象销毁后继续存活。例如:
    fn main() {
        let result;
        {
            let num = 5;
            result = # // 这里会报错,因为num的生命周期在这个块结束,result的生命周期长于num
        }
        // println!("{}", result); 
    }
    

在并发编程中防止数据竞争

  1. 数据竞争的定义:数据竞争发生在多个线程同时访问同一内存位置,其中至少有一个是写操作,并且没有适当的同步机制。
  2. Rust借用规则防止数据竞争的原理
    • 由于同一时间要么只有不可变借用(允许多个),要么只有一个可变借用,这就保证了同一时间不会有多个线程对同一数据进行写操作,或者读操作与写操作同时进行。
    • 例如,假设有两个线程,线程1尝试可变借用数据进行写操作,线程2尝试不可变借用数据进行读操作。根据借用规则,这是不允许的,Rust编译器会在编译时就检测到这个错误。
    • 下面是一个简单的多线程并发代码示例:
    use std::thread;
    fn main() {
        let mut data = String::from("hello");
        let handle = thread::spawn(|| {
            // 这里如果要对data进行操作,需要可变借用
            // 但在主线程中data已经是可变的,所以这里会报错
            // let mut new_data = &mut data;
            // new_data.push_str(", world");
            // println!("{}", new_data);
        });
        // 主线程中对data进行操作
        data.push_str(", rust");
        handle.join().unwrap();
        println!("{}", data);
    }
    
    • 在上述代码中,如果尝试在子线程中获取对data的可变借用,由于主线程中已经有对data的可变借用,编译器会报错,从而防止了数据竞争。这确保了在并发编程中,对共享数据的访问是安全的,避免了数据竞争问题。