MST

星途 面试题库

面试题:Rust线程同步函数调用中的数据竞争问题

在Rust中,假设你有多个线程同时调用一个共享资源相关的同步函数,可能会出现数据竞争问题。请描述一种场景,并说明如何使用Rust提供的同步原语(如Mutex、Arc等)来解决这个问题。
32.1万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

场景描述

假设有一个银行账户类 BankAccount,包含账户余额字段。多个线程可能同时对该账户进行存款和取款操作,如果没有同步机制,就可能出现数据竞争。例如,线程A读取当前余额为100,线程B也读取余额为100,然后线程A存款50,余额变为150,线程B取款30,它认为当前余额还是100,所以取完后余额变为70,但正确结果应该是120。

解决方法

使用 MutexArc 来解决这个问题。Arc(原子引用计数)用于在多个线程间共享数据,Mutex(互斥锁)用于保证同一时间只有一个线程能访问共享数据。

以下是示例代码:

use std::sync::{Arc, Mutex};
use std::thread;

// 定义银行账户结构体
struct BankAccount {
    balance: i32,
}

impl BankAccount {
    fn new(initial_balance: i32) -> Self {
        BankAccount {
            balance: initial_balance,
        }
    }

    fn deposit(&mut self, amount: i32) {
        self.balance += amount;
    }

    fn withdraw(&mut self, amount: i32) -> bool {
        if self.balance >= amount {
            self.balance -= amount;
            true
        } else {
            false
        }
    }
}

fn main() {
    // 使用Arc和Mutex来共享银行账户
    let account = Arc::new(Mutex::new(BankAccount::new(100)));
    let handles = (0..10).map(|_| {
        let account_clone = account.clone();
        thread::spawn(move || {
            let mut account = account_clone.lock().unwrap();
            account.deposit(10);
            account.withdraw(5);
        })
    }).collect::<Vec<_>>();

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

    let final_balance = account.lock().unwrap().balance;
    println!("Final balance: {}", final_balance);
}

在上述代码中:

  1. Arc<Mutex<BankAccount>> 确保 BankAccount 实例可以在多个线程间安全共享,并且同一时间只有一个线程能获取 Mutex 的锁从而访问 BankAccount
  2. account_clone.lock().unwrap() 获取锁,如果获取成功则返回一个智能指针,通过它可以安全地访问和修改 BankAccount 的数据。这样就避免了数据竞争问题。