X-Git-Url: https://git.ralfj.de/rust-101.git/blobdiff_plain/18e6fec08956d95a3fd1b4b1ef2a7bb9620c5fcf..ccf679adb3790903849f7d85b970b67582220952:/solutions/src/counter.rs diff --git a/solutions/src/counter.rs b/solutions/src/counter.rs new file mode 100644 index 0000000..265fb99 --- /dev/null +++ b/solutions/src/counter.rs @@ -0,0 +1,56 @@ +use std::sync::{Arc, RwLock}; +use std::thread; + +#[derive(Clone)] +struct ConcurrentCounter(Arc>); + +impl ConcurrentCounter { + // The constructor should not be surprising. + pub fn new(val: usize) -> Self { + ConcurrentCounter(Arc::new(RwLock::new(val))) + } + + pub fn increment(&self, by: usize) { + let mut counter = self.0.write().unwrap(); + *counter = *counter + by; + } + + pub fn get(&self) -> usize { + let counter = self.0.read().unwrap(); + *counter + } +} + +// Now our counter is ready for action. +pub fn main() { + let counter = ConcurrentCounter::new(0); + + // We clone the counter for the first thread, which increments it by 2 every 15ms. + let counter1 = counter.clone(); + let handle1 = thread::spawn(move || { + for _ in 0..10 { + thread::sleep_ms(15); + counter1.increment(2); + } + }); + + // The second thread increments the counter by 3 every 20ms. + let counter2 = counter.clone(); + let handle2 = thread::spawn(move || { + for _ in 0..10 { + thread::sleep_ms(20); + counter2.increment(3); + } + }); + + // Now we want to watch the threads working on the counter. + for _ in 0..50 { + thread::sleep_ms(5); + println!("Current value: {}", counter.get()); + } + + // Finally, wait for all the threads to finish to be sure we can catch the counter's final value. + handle1.join().unwrap(); + handle2.join().unwrap(); + println!("Final value: {}", counter.get()); +}