···2424 for handle in handles {
2525 // TODO: Collect the results of all threads into the `results` vector.
2626 // Use the `JoinHandle` struct which is returned by `thread::spawn`.
2727+ results.push(handle.join().unwrap());
2728 }
28292930 if results.len() != 10 {
+8-4
exercises/20_threads/threads2.rs
···22// work. But this time, the spawned threads need to be in charge of updating a
33// shared value: `JobStatus.jobs_done`
4455-use std::{sync::Arc, thread, time::Duration};
55+use std::{
66+ sync::{Arc, Mutex},
77+ thread,
88+ time::Duration,
99+};
610711struct JobStatus {
812 jobs_done: u32,
···10141115fn main() {
1216 // TODO: `Arc` isn't enough if you want a **mutable** shared state.
1313- let status = Arc::new(JobStatus { jobs_done: 0 });
1717+ let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
14181519 let mut handles = Vec::new();
1620 for _ in 0..10 {
···1923 thread::sleep(Duration::from_millis(250));
20242125 // TODO: You must take an action before you update a shared value.
2222- status_shared.jobs_done += 1;
2626+ status_shared.lock().unwrap().jobs_done += 1;
2327 });
2428 handles.push(handle);
2529 }
···3034 }
31353236 // TODO: Print the value of `JobStatus.jobs_done`.
3333- println!("Jobs done: {}", todo!());
3737+ println!("Jobs done: {}", status.lock().unwrap().jobs_done);
3438}
+3-1
exercises/20_threads/threads3.rs
···1717fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
1818 // TODO: We want to send `tx` to both threads. But currently, it is moved
1919 // into the first thread. How could you solve this problem?
2020+ let tx2 = tx.clone();
2121+2022 thread::spawn(move || {
2123 for val in q.first_half {
2224 println!("Sending {val:?}");
···2830 thread::spawn(move || {
2931 for val in q.second_half {
3032 println!("Sending {val:?}");
3131- tx.send(val).unwrap();
3333+ tx2.send(val).unwrap();
3234 thread::sleep(Duration::from_millis(250));
3335 }
3436 });
+35-2
solutions/20_threads/threads1.rs
···11+// This program spawns multiple threads that each runs for at least 250ms, and
22+// each thread returns how much time it took to complete. The program should
33+// wait until all the spawned threads have finished and should collect their
44+// return values into a vector.
55+66+use std::{
77+ thread,
88+ time::{Duration, Instant},
99+};
1010+111fn main() {
22- // DON'T EDIT THIS SOLUTION FILE!
33- // It will be automatically filled after you finish the exercise.
1212+ let mut handles = Vec::new();
1313+ for i in 0..10 {
1414+ let handle = thread::spawn(move || {
1515+ let start = Instant::now();
1616+ thread::sleep(Duration::from_millis(250));
1717+ println!("Thread {i} done");
1818+ start.elapsed().as_millis()
1919+ });
2020+ handles.push(handle);
2121+ }
2222+2323+ let mut results = Vec::new();
2424+ for handle in handles {
2525+ // Collect the results of all threads into the `results` vector.
2626+ results.push(handle.join().unwrap());
2727+ }
2828+2929+ if results.len() != 10 {
3030+ panic!("Oh no! Some thread isn't done yet!");
3131+ }
3232+3333+ println!();
3434+ for (i, result) in results.into_iter().enumerate() {
3535+ println!("Thread {i} took {result}ms");
3636+ }
437}
+39-2
solutions/20_threads/threads2.rs
···11+// Building on the last exercise, we want all of the threads to complete their
22+// work. But this time, the spawned threads need to be in charge of updating a
33+// shared value: `JobStatus.jobs_done`
44+55+use std::{
66+ sync::{Arc, Mutex},
77+ thread,
88+ time::Duration,
99+};
1010+1111+struct JobStatus {
1212+ jobs_done: u32,
1313+}
1414+115fn main() {
22- // DON'T EDIT THIS SOLUTION FILE!
33- // It will be automatically filled after you finish the exercise.
1616+ // `Arc` isn't enough if you want a **mutable** shared state.
1717+ // We need to wrap the value with a `Mutex`.
1818+ let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
1919+ // ^^^^^^^^^^^ ^
2020+2121+ let mut handles = Vec::new();
2222+ for _ in 0..10 {
2323+ let status_shared = Arc::clone(&status);
2424+ let handle = thread::spawn(move || {
2525+ thread::sleep(Duration::from_millis(250));
2626+2727+ // Lock before you update a shared value.
2828+ status_shared.lock().unwrap().jobs_done += 1;
2929+ // ^^^^^^^^^^^^^^^^
3030+ });
3131+ handles.push(handle);
3232+ }
3333+3434+ // Waiting for all jobs to complete.
3535+ for handle in handles {
3636+ handle.join().unwrap();
3737+ }
3838+3939+ println!("Jobs done: {}", status.lock().unwrap().jobs_done);
4040+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
441}
+60-2
solutions/20_threads/threads3.rs
···11+use std::{sync::mpsc, thread, time::Duration};
22+33+struct Queue {
44+ first_half: Vec<u32>,
55+ second_half: Vec<u32>,
66+}
77+88+impl Queue {
99+ fn new() -> Self {
1010+ Self {
1111+ first_half: vec![1, 2, 3, 4, 5],
1212+ second_half: vec![6, 7, 8, 9, 10],
1313+ }
1414+ }
1515+}
1616+1717+fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
1818+ // Clone the sender `tx` first.
1919+ let tx_clone = tx.clone();
2020+ thread::spawn(move || {
2121+ for val in q.first_half {
2222+ println!("Sending {val:?}");
2323+ // Then use the clone in the first thread. This means that
2424+ // `tx_clone` is moved to the first thread and `tx` to the second.
2525+ tx_clone.send(val).unwrap();
2626+ thread::sleep(Duration::from_millis(250));
2727+ }
2828+ });
2929+3030+ thread::spawn(move || {
3131+ for val in q.second_half {
3232+ println!("Sending {val:?}");
3333+ tx.send(val).unwrap();
3434+ thread::sleep(Duration::from_millis(250));
3535+ }
3636+ });
3737+}
3838+139fn main() {
22- // DON'T EDIT THIS SOLUTION FILE!
33- // It will be automatically filled after you finish the exercise.
4040+ // You can optionally experiment here.
4141+}
4242+4343+#[cfg(test)]
4444+mod tests {
4545+ use super::*;
4646+4747+ #[test]
4848+ fn threads3() {
4949+ let (tx, rx) = mpsc::channel();
5050+ let queue = Queue::new();
5151+5252+ send_tx(queue, tx);
5353+5454+ let mut received = Vec::with_capacity(10);
5555+ for value in rx {
5656+ received.push(value);
5757+ }
5858+5959+ received.sort();
6060+ assert_eq!(received, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
6161+ }
462}