Rust
Arc<Mutex> state
Manage shared state with Arc<Mutex<>>.
Arc<Mutex> state
The chat room's list of who's connected is shared state that every client thread reads and changes. It's shared with Arc<Mutex<Oda>>; each change happens under a short lock:
struct Oda {
uyeler: Vec<String>,
}
impl Oda {
fn katil(&mut self, ad: &str) { self.uyeler.push(ad.to_string()); }
fn ayril(&mut self, ad: &str) { self.uyeler.retain(|k| k != ad); }
}
let oda = Arc::new(Mutex::new(Oda { uyeler: Vec::new() }));
Keeping the methods on Oda separates locking code from business logic: oda.lock().unwrap().katil("ece").
Joining from threads
Each client thread adds its own name to the room. Since the threads' finishing order is undefined, the list is sorted before printing:
let tutucular: Vec<_> = ["ece", "can", "ali"]
.into_iter()
.map(|ad| {
let oda = Arc::clone(&oda);
thread::spawn(move || oda.lock().unwrap().katil(ad))
})
.collect();
for t in tutucular { t.join().unwrap(); }
oda.lock().unwrap().ayril("can");
Exercise Room state
Write the Oda type above and share it with Arc<Mutex<Oda>>. Let ece, can and ali join from separate threads; once they're all done, let can leave. Sort the user list and print it with {:?}.
Show example solution
use std::sync::{Arc, Mutex};
use std::thread;
struct Oda {
uyeler: Vec<String>,
}
impl Oda {
fn katil(&mut self, ad: &str) {
self.uyeler.push(ad.to_string());
}
fn ayril(&mut self, ad: &str) {
self.uyeler.retain(|k| k != ad);
}
}
fn main() {
let oda = Arc::new(Mutex::new(Oda { uyeler: Vec::new() }));
let tutucular: Vec<_> = ["ece", "can", "ali"]
.into_iter()
.map(|ad| {
let oda = Arc::clone(&oda);
thread::spawn(move || oda.lock().unwrap().katil(ad))
})
.collect();
for t in tutucular {
t.join().unwrap();
}
oda.lock().unwrap().ayril("can");
let mut liste = oda.lock().unwrap().uyeler.clone();
liste.sort();
println!("{:?}", liste);
}
Test yourself
-
Why is writing to a client over the network while holding the lock a bad idea?
- A slow client holds the lock long and freezes the whole room
- The write fails
- It doesn't compile
- It isn't bad
Show answer
A slow client holds the lock long and freezes the whole room — Under the lock, only take a copy of the list; do the I/O after releasing the lock.
-
Remove the leaver
fn ayril(&mut self, ad: &str) {
self.uyeler.____(|k| k != ad);
}
Show answer
fn ayril(&mut self, ad: &str) {
self.uyeler.retain(|k| k != ad);
}
-
Operation and room state
- ece, can, ali joined
- 3 users
- can left
- 2 users
- Sorted list
- ["ali", "ece"]
- lock() held briefly
- The room doesn't freeze
Next lesson: unsafe block