# Shared-State Concurrency In previous phrase "Not communicating by sharing memroy" : Multiple ownership model. Multiple sources can access memory at the same time = COMPLEX but also effective. ## Mutexes - One Thread at a Time `mutex` = mutual exclusion, only 1 exclusive accessor. You have to ask permission to the `mutex`'s lock to access data. - MUST attemp to acquire the lock before using data (ask for permission) - When you're done, express so other can use it Basically like borrowing a book from a library. ## API of `Mutex` ```rust fn mutex() { let m = Mutex::new(5); // Create a mutex holding a var { let mut num = m.lock().unwrap(); // Ask for permission - Blocks execution // The call will fail if another thread holds the lock and fucks up, so this thread to treat that case. // Returns a `smart pointer` type `MutexGuard` that implements the `Deref` trait so we can get to the value with ownership. *num = 6; // `MutexGuard` also implements `Drop` so the lock becomes available when dropped } println!("m = {:?}", m); } ``` ### Sharing a Mutex between Threads ```rust let counter = Mutex::new(0); let mut handles = vec![]; // This will happen 10 times // We move ownership of both handle and counter on the 1st iteration // Next iterations can't move, because it is not main who owns them, its the 1st iteration that owns them... for _ in 0..10 { let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); ``` ### Multiple Ownership in Multiple Threads We can try and us `Rc`: ```rust use std::rc::Rc; fn mutex_multiple_owners_Rc_2() { let counter = Rc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let counter = Rc::clone(&counter); // Rc is not thread safe let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); } ``` We get this error: ``` error[E0277]: `Rc>` cannot be sent between threads safely --> src/main.rs:11:22 | 11 | let handle = thread::spawn(move || { | ______________________^^^^^^^^^^^^^_- | | | | | `Rc>` cannot be sent between threads safely 12 | | let mut num = counter.lock().unwrap(); 13 | | 14 | | *num += 1; 15 | | }); | |_________- within this `[closure@src/main.rs:11:36: 15:10]` | = help: within `[closure@src/main.rs:11:36: 15:10]`, the trait `Send` is not implemented for `Rc>` = note: required because it appears within the type `[closure@src/main.rs:11:36: 15:10]` For more information about this error, try `rustc --explain E0277`. error: could not compile `shared-state` due to previous error ``` In short, `Rc` is not safe in multithreaded environments, it does not implement the `Send` trait which is used to pass around info between threads/channels. Why is it not safe? Because each call to `clone()` and `drop()` does not use any safety measures to make sure data is synced. Imagine 2 threads call `clone()` at the same time, One would increment `4->5` and the other do the same `4->5`, but we have increased 2 times. Then with drops the same could happen or even worse, the value caused to be dropped early and another thread use it! ### Atomic Reference Counting - `Arc` Basically thread-safe `Rc` Atomics are types that can only be accessed 1 at a time, guaranteed by the language and OS architechture But that 1 at a time, has a cost of waiting, so trade safety for performance, be smart when using them. ```rust use std::sync::Arc; fn mutex_multiple_owners_Arc_3() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let counter_in = Arc::clone(&counter); // We borrow counter intro loop just to clone it // Move each clone into every thread // 1 clone per thread of the Mutex // Make it atomic so actions to it are also safe. let handle = thread::spawn(move || { let mut num = counter_in.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); } ``` ## Similarities - RefCell/Rc vs Mutex/Arc Basically they are very similar, `Mutex` allows getting a mutable reference from an immutable variable (Interior Mutability) - Like `Cell` Types. Same as explained with `Rc/Arc`. `Mutex` are not safe by default, we can create `deadlock` which is when 2 or more threads lock a resource each, then try to acquire the lock of the resource the other has locked: ```rust fn deadlock() { let t1_var = Arc::new(Mutex::new(0)); let t2_var = Arc::new(Mutex::new(0)); let t1_clone = t1_var.clone(); let t2_clone = t2_var.clone(); let handle1 = thread::spawn(move || { let mut t1 = t1_var.lock().unwrap(); thread::sleep(Duration::from_secs(2)); println!("Got t1 lock, try getting t2 lock..."); let mut t2 = t2_var.lock().unwrap(); println!("This never prints..."); }); let handle2 = thread::spawn(move || { let mut t2 = t2_clone.lock().unwrap(); thread::sleep(Duration::from_secs(2)); println!("Got t2 lock, try getting t1 lock..."); let mut t1 = t1_clone.lock().unwrap(); println!("This never prints..."); }); println!("Threads Spawned..."); handle1.join().unwrap(); handle2.join().unwrap(); } ``` This code will lock each thread a variable, then wait a couple seconds to make sure the other thread locked the other. Then try to lock the one the other thread has -> Deadlock.