如何在Rust中移动带有Mutex数据的struct变量?

4dc9hkyq  于 2024-01-08  发布在  其他
关注(0)|答案(1)|浏览(117)

我正在尝试翻译一个使用Bank对象的C程序,该程序使用的方法可以更改帐户的余额并使用互斥锁,因此这可以并行发生。在这个程序中,每个帐户都有一个锁,我需要在修改数据之前访问它。在C中,Bank对象是全局的,有许多锁来保护数据。在Rust中,我创建了一个Struct Bank,在那里我尝试使用Arc<Mutex>和Mutex,以解决将数据移动到线程的问题,因为它不实现Copy。我完全知道我可以只放入Arc<Mutex>,但为了使其更类似于C++代码,我想尝试只保护特定数据。下面是一些代码:
Bank.rs

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

#[derive(Debug)]
pub struct Account {
    account_id: i32,
    balance: Arc<Mutex<i64>>,
}

#[derive(Debug)]
pub struct Bank {
    num: Arc<Mutex<i32>>,
    num_succ: Arc<Mutex<i32>>,
    num_fail: Arc<Mutex<i32>>,
    accounts: Vec<Account>,
}

pub fn init(n: i32) -> Bank {
    let mut accounts: Vec<Account> = Vec::new();
    for i in 0..n {
        accounts.push(Account {
            account_id: i,
            balance: Arc::new(Mutex::new(0)),
        });
    }
    Bank {
        num: Arc::new(Mutex::new(0)),
        num_succ: Arc::new(Mutex::new(0)),
        num_fail: Arc::new(Mutex::new(0)),
        accounts: accounts,
    }
}

impl Bank {
    pub fn print_account(&self) {
        for i in &self.accounts {
            let balance_lock = i.balance.lock().unwrap();
            println!("ID# {} | {}", i.account_id, balance_lock);
        }

        println!(
            "Success: {} Fails: {}", 
            self.num_succ.lock().unwrap(), 
            self.num_fail.lock().unwrap(),
        );
    }
    pub fn record_succ(&self, message: String) {
        let mut succ_lock = self.num_succ.lock().unwrap();
        println!("{message}");
        *succ_lock+=1;
    }
    pub fn record_fail(&self, message: &str) {
        let mut fail_lock = self.num_fail.lock().unwrap();
        println!("{message}");
        *fail_lock+=1;
    }
    pub fn deposit(&self, worker_id: i32, ledger_id: i32, account_id: i32, amount: i32) {
        let account = self.accounts.get(account_id as usize).unwrap();
        let mut balance_lock = account.balance.lock().unwrap();
        *balance_lock += amount as i64;
        self.record_succ(format!("Worker {worker_id} completed ledger {ledger_id}: deposit {} into account {account_id}", *balance_lock));
    }
}

字符串
main.rs

use std::{
    process,
    thread,
    env,
};
use crate::bank::*;

pub mod bank;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        eprintln!("Usage: {} <num_of_threads>\n", args[0]);
        process::exit(1);
    }
    let num = args[1].parse::<i32>().unwrap_or(-1);
    
    let bank = bank::init(10);
    let mut workers = Vec::new();

    for id in 0..num {
        // ERROR on move: move occurs because `bank` has type `bank::Bank`, which does not implement the `Copy` trait
        let worker = thread::spawn(move || worker(id, &bank));
        workers.push(worker);
    }
    for worker in workers {
        worker.join().unwrap();
    }
}

fn worker(worker_id: i32, bank: &Bank) {
    let mut size = i32::MAX;
    bank.deposit(worker_id, 0, 1, 800);
}


我们的目标是锁定特定的账户余额并并行修改。我有几个方法可以对自己进行这些操作。

zbq4xfa0

zbq4xfa01#

不需要对每个字段都使用Arc<Mutex>,只使用Mutex,并将整个Bank Package 在Arc中。然后您可以克隆它:

use crate::bank::*;
use std::sync::Arc;
use std::{env, process, thread};

pub mod bank {
    use std::sync::{Arc, Mutex};

    #[derive(Debug)]
    pub struct Account {
        account_id: i32,
        balance: Mutex<i64>,
    }

    #[derive(Debug)]
    pub struct Bank {
        num: Mutex<i32>,
        num_succ: Mutex<i32>,
        num_fail: Mutex<i32>,
        accounts: Vec<Account>,
    }

    pub fn init(n: i32) -> Arc<Bank> {
        let mut accounts: Vec<Account> = Vec::new();
        for i in 0..n {
            accounts.push(Account {
                account_id: i,
                balance: Mutex::new(0),
            });
        }
        Arc::new(Bank {
            num: Mutex::new(0),
            num_succ: Mutex::new(0),
            num_fail: Mutex::new(0),
            accounts: accounts,
        })
    }

    impl Bank {
        pub fn print_account(&self) {
            for i in &self.accounts {
                let balance_lock = i.balance.lock().unwrap();
                println!("ID# {} | {}", i.account_id, balance_lock);
            }

            println!(
                "Success: {} Fails: {}",
                self.num_succ.lock().unwrap(),
                self.num_fail.lock().unwrap(),
            );
        }
        pub fn record_succ(&self, message: String) {
            let mut succ_lock = self.num_succ.lock().unwrap();
            println!("{message}");
            *succ_lock += 1;
        }
        pub fn record_fail(&self, message: &str) {
            let mut fail_lock = self.num_fail.lock().unwrap();
            println!("{message}");
            *fail_lock += 1;
        }
        pub fn deposit(&self, worker_id: i32, ledger_id: i32, account_id: i32, amount: i32) {
            let account = self.accounts.get(account_id as usize).unwrap();
            let mut balance_lock = account.balance.lock().unwrap();
            *balance_lock += amount as i64;
            self.record_succ(format!("Worker {worker_id} completed ledger {ledger_id}: deposit {} into account {account_id}", *balance_lock));
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        eprintln!("Usage: {} <num_of_threads>\n", args[0]);
        process::exit(1);
    }
    let num = args[1].parse::<i32>().unwrap_or(-1);

    let bank = bank::init(10);
    let mut workers = Vec::new();

    for id in 0..num {
        // ERROR on move: move occurs because `bank` has type `bank::Bank`, which does not implement the `Copy` trait
        let worker = thread::spawn({
            let bank = Arc::clone(&bank);
            move || worker(id, &bank)
        });
        workers.push(worker);
    }
    for worker in workers {
        worker.join().unwrap();
    }
}

fn worker(worker_id: i32, bank: &Bank) {
    let mut size = i32::MAX;
    bank.deposit(worker_id, 0, 1, 800);
}

字符串

相关问题