Add first version of part 14
[rust-101.git] / solutions / src / counter.rs
1 use std::sync::{Arc, RwLock};
2 use std::thread;
3
4 #[derive(Clone)]
5 struct ConcurrentCounter(Arc<RwLock<usize>>);
6
7 impl ConcurrentCounter {
8     // The constructor should not be surprising.
9     pub fn new(val: usize) -> Self {
10         ConcurrentCounter(Arc::new(RwLock::new(val)))
11     }
12
13     pub fn increment(&self, by: usize) {
14         let mut counter = self.0.write().unwrap();
15         *counter = *counter + by;
16     }
17
18     pub fn get(&self) -> usize {
19         let counter = self.0.read().unwrap();
20         *counter
21     }
22 }
23
24 // Now our counter is ready for action.
25 pub fn main() {
26     let counter = ConcurrentCounter::new(0);
27
28     // We clone the counter for the first thread, which increments it by 2 every 15ms.
29     let counter1 = counter.clone();
30     let handle1 = thread::spawn(move || {
31         for _ in 0..10 {
32             thread::sleep_ms(15);
33             counter1.increment(2);
34         }
35     });
36
37     // The second thread increments the counter by 3 every 20ms.
38     let counter2 = counter.clone();
39     let handle2 = thread::spawn(move || {
40         for _ in 0..10 {
41             thread::sleep_ms(20);
42             counter2.increment(3);
43         }
44     });
45
46     // Now we want to watch the threads working on the counter.
47     for _ in 0..50 {
48         thread::sleep_ms(5);
49         println!("Current value: {}", counter.get());
50     }
51
52     // Finally, wait for all the threads to finish to be sure we can catch the counter's final value.
53     handle1.join().unwrap();
54     handle2.join().unwrap();
55     println!("Final value: {}", counter.get());
56 }