CS3984 Computer Systems in Rust



Atomicity Violations

  • A bug pattern where multiple operations on shared data need to be atomic to ensure correct functioning of application, but the program performs only individual operations atomically.

  • Common pattern is

lock shared stateobtain information from shared state and store it in local varunlock shared state/* meanwhile, other thread may change the state */(re-) lock shared stateact on previously obtained informationunlock shared state


  • Rust’s safety mechanisms do not avoid this

Atomicity Violation

use std::sync::Mutex;
fn main() {
    let protected_shared_counter = Mutex::new(0);
    std::thread::scope(|s| {
        for _i in 0..4 {
            let counter = &protected_shared_counter;
            s.spawn(move || {
                for _i in 0..1000000 {
                    let mut current_value = 0;
                    if let Ok(v) = counter.lock() { current_value = *v; }
                    current_value += 1;
                    if let Ok(mut v) = counter.lock() { *v = current_value; }
                }
            });
        }
    });
    let final_value = protected_shared_counter.lock().unwrap();
    println!("final_value {}", final_value);
}


Resource Deadlocks

  • Deadlocks occurring when multiple threads attempt to make use of resources

  • Coffman Conditions:

    • mutually exclusive access
    • sequential acquisition of multiple resources (hold-and-wait)
    • inability to preempt access to resource
    • circular wait

Deadlock Canonical Example

use std::sync::Mutex;
fn main() {
    let account_a = Mutex::new(50000);
    let account_b = Mutex::new(50000);
    std::thread::scope(|s| {
        for (from, to) in vec![(&account_a, &account_b), (&account_b, &account_a)] {
            s.spawn(move || {
                for _i in 0..3000 {
                    if let Ok(mut u) = from.lock() {
                        if let Ok(mut v) = to.lock() { *u -= 1; *v += 1; }
                    }
                }
            });
        }
    });
    println!("final amounts {} {}", account_a.lock().unwrap(), 
             account_b.lock().unwrap());
}