PR3-Rust-SS26/G-concurrency/racecondition.rs

58 lines
2.2 KiB
Rust

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn main() {
// A shared bank account starting with $100
let account_balance = Arc::new(Mutex::new(100));
// Thread A: Attempts to withdraw $80
let balance_clone1 = Arc::clone(&account_balance);
let handle1 = thread::spawn(move || {
// 1. CHECK: Lock the account just to check the balance
let current_balance = *balance_clone1.lock().unwrap();
if current_balance >= 80 {
println!("Thread A: Balance is ${}. Approval granted!", current_balance);
// Simulate a tiny delay (e.g., network latency or CPU context switch)
// This gives Thread B time to sneak in and check the balance
thread::sleep(Duration::from_millis(5));
// 2. ACT: Lock again to deduct the money
let mut balance_guard = balance_clone1.lock().unwrap();
*balance_guard -= 80;
println!("Thread A: Successfully withdrew $80.");
} else {
println!("Thread A: Declined. Insufficient funds.");
}
});
// Thread B: Simultaneously attempts to withdraw $80
let balance_clone2 = Arc::clone(&account_balance);
let handle2 = thread::spawn(move || {
// 1. CHECK: Lock the account just to check the balance
let current_balance = *balance_clone2.lock().unwrap();
if current_balance >= 80 {
println!("Thread B: Balance is ${}. Approval granted!", current_balance);
// Simulate a tiny delay (e.g., network latency or CPU context switch)
// This gives Thread B time to sneak in and check the balance
thread::sleep(Duration::from_millis(5));
// 2. ACT: Lock again to deduct the money
let mut balance_guard = balance_clone2.lock().unwrap();
*balance_guard -= 80;
println!("Thread B: Successfully withdrew $80.");
} else {
println!("Thread B: Declined. Insufficient funds.");
}
});
handle1.join().unwrap();
handle2.join().unwrap();
// Final result
println!("Final Bank Balance: ${}", *account_balance.lock().unwrap());
}