diff --git a/exercises/20_threads/threads3.rs b/exercises/20_threads/threads3.rs index 37810cf..30ac8dd 100644 --- a/exercises/20_threads/threads3.rs +++ b/exercises/20_threads/threads3.rs @@ -1,7 +1,4 @@ -use std::sync::mpsc; -use std::sync::Arc; -use std::thread; -use std::time::Duration; +use std::{sync::mpsc, thread, time::Duration}; struct Queue { length: u32, @@ -11,7 +8,7 @@ struct Queue { impl Queue { fn new() -> Self { - Queue { + Self { length: 10, first_half: vec![1, 2, 3, 4, 5], second_half: vec![6, 7, 8, 9, 10], @@ -19,20 +16,22 @@ impl Queue { } } -fn send_tx(q: Queue, tx: mpsc::Sender) -> () { +fn send_tx(q: Queue, tx: mpsc::Sender) { + // TODO: We want to send `tx` to both threads. But currently, it is moved + // into the frist thread. How could you solve this problem? thread::spawn(move || { for val in q.first_half { - println!("sending {:?}", val); + println!("Sending {val:?}"); tx.send(val).unwrap(); - thread::sleep(Duration::from_secs(1)); + thread::sleep(Duration::from_millis(250)); } }); thread::spawn(move || { for val in q.second_half { - println!("sending {:?}", val); + println!("Sending {val:?}"); tx.send(val).unwrap(); - thread::sleep(Duration::from_secs(1)); + thread::sleep(Duration::from_millis(250)); } }); } @@ -55,11 +54,11 @@ mod tests { let mut total_received: u32 = 0; for received in rx { - println!("Got: {}", received); + println!("Got: {received}"); total_received += 1; } - println!("total numbers received: {}", total_received); + println!("Number of received values: {total_received}"); assert_eq!(total_received, queue_length); } } diff --git a/rustlings-macros/info.toml b/rustlings-macros/info.toml index ab8c121..24dcdee 100644 --- a/rustlings-macros/info.toml +++ b/rustlings-macros/info.toml @@ -1076,10 +1076,11 @@ An alternate way to handle concurrency between threads is to use an `mpsc` With both a sending end and a receiving end, it's possible to send values in one thread and receive them in another. -Multiple producers are possible by using clone() to create a duplicate of the +Multiple producers are possible by using `clone()` to create a duplicate of the original sending end. -See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info.""" +Related section in The Book: +https://doc.rust-lang.org/book/ch16-02-message-passing.html""" # MACROS diff --git a/solutions/20_threads/threads3.rs b/solutions/20_threads/threads3.rs index 4e18198..cd2dfbe 100644 --- a/solutions/20_threads/threads3.rs +++ b/solutions/20_threads/threads3.rs @@ -1 +1,66 @@ -// Solutions will be available before the stable release. Thank you for testing the beta version 🥰 +use std::{sync::mpsc, thread, time::Duration}; + +struct Queue { + length: u32, + first_half: Vec, + second_half: Vec, +} + +impl Queue { + fn new() -> Self { + Self { + length: 10, + first_half: vec![1, 2, 3, 4, 5], + second_half: vec![6, 7, 8, 9, 10], + } + } +} + +fn send_tx(q: Queue, tx: mpsc::Sender) { + // Clone the sender `tx` first. + let tx_clone = tx.clone(); + thread::spawn(move || { + for val in q.first_half { + println!("Sending {val:?}"); + // Then use the clone in the first thread. This means that + // `tx_clone` is moved to the first thread and `tx` to the second. + tx_clone.send(val).unwrap(); + thread::sleep(Duration::from_millis(250)); + } + }); + + thread::spawn(move || { + for val in q.second_half { + println!("Sending {val:?}"); + tx.send(val).unwrap(); + thread::sleep(Duration::from_millis(250)); + } + }); +} + +fn main() { + // You can optionally experiment here. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn threads3() { + let (tx, rx) = mpsc::channel(); + let queue = Queue::new(); + let queue_length = queue.length; + + send_tx(queue, tx); + + let mut total_received: u32 = 0; + for received in rx { + println!("Got: {received}"); + total_received += 1; + } + + println!("Number of received values: {total_received}"); + assert_eq!(total_received, queue_length); + } +}