diff options
Diffstat (limited to 'rustlings/exercises/20_threads')
| -rw-r--r-- | rustlings/exercises/20_threads/README.md | 10 | ||||
| -rw-r--r-- | rustlings/exercises/20_threads/threads1.rs | 37 | ||||
| -rw-r--r-- | rustlings/exercises/20_threads/threads2.rs | 34 | ||||
| -rw-r--r-- | rustlings/exercises/20_threads/threads3.rs | 60 |
4 files changed, 141 insertions, 0 deletions
diff --git a/rustlings/exercises/20_threads/README.md b/rustlings/exercises/20_threads/README.md new file mode 100644 index 0000000..0b32fb1 --- /dev/null +++ b/rustlings/exercises/20_threads/README.md @@ -0,0 +1,10 @@ +# Threads + +In most current operating systems, an executed program's code is run in a process, and the operating system manages multiple processes at once. +Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads. + +## Further information + +- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) +- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html) +- [Using Message Passing to Transfer Data Between Threads](https://doc.rust-lang.org/book/ch16-02-message-passing.html) diff --git a/rustlings/exercises/20_threads/threads1.rs b/rustlings/exercises/20_threads/threads1.rs new file mode 100644 index 0000000..dbc64b1 --- /dev/null +++ b/rustlings/exercises/20_threads/threads1.rs @@ -0,0 +1,37 @@ +// This program spawns multiple threads that each runs for at least 250ms, and +// each thread returns how much time it took to complete. The program should +// wait until all the spawned threads have finished and should collect their +// return values into a vector. + +use std::{ + thread, + time::{Duration, Instant}, +}; + +fn main() { + let mut handles = Vec::new(); + for i in 0..10 { + let handle = thread::spawn(move || { + let start = Instant::now(); + thread::sleep(Duration::from_millis(250)); + println!("Thread {i} done"); + start.elapsed().as_millis() + }); + handles.push(handle); + } + + let mut results = Vec::new(); + for handle in handles { + // TODO: Collect the results of all threads into the `results` vector. + // Use the `JoinHandle` struct which is returned by `thread::spawn`. + } + + if results.len() != 10 { + panic!("Oh no! Some thread isn't done yet!"); + } + + println!(); + for (i, result) in results.into_iter().enumerate() { + println!("Thread {i} took {result}ms"); + } +} diff --git a/rustlings/exercises/20_threads/threads2.rs b/rustlings/exercises/20_threads/threads2.rs new file mode 100644 index 0000000..7020cb9 --- /dev/null +++ b/rustlings/exercises/20_threads/threads2.rs @@ -0,0 +1,34 @@ +// Building on the last exercise, we want all of the threads to complete their +// work. But this time, the spawned threads need to be in charge of updating a +// shared value: `JobStatus.jobs_done` + +use std::{sync::Arc, thread, time::Duration}; + +struct JobStatus { + jobs_done: u32, +} + +fn main() { + // TODO: `Arc` isn't enough if you want a **mutable** shared state. + let status = Arc::new(JobStatus { jobs_done: 0 }); + + let mut handles = Vec::new(); + for _ in 0..10 { + let status_shared = Arc::clone(&status); + let handle = thread::spawn(move || { + thread::sleep(Duration::from_millis(250)); + + // TODO: You must take an action before you update a shared value. + status_shared.jobs_done += 1; + }); + handles.push(handle); + } + + // Waiting for all jobs to complete. + for handle in handles { + handle.join().unwrap(); + } + + // TODO: Print the value of `JobStatus.jobs_done`. + println!("Jobs done: {}", todo!()); +} diff --git a/rustlings/exercises/20_threads/threads3.rs b/rustlings/exercises/20_threads/threads3.rs new file mode 100644 index 0000000..6d16bd9 --- /dev/null +++ b/rustlings/exercises/20_threads/threads3.rs @@ -0,0 +1,60 @@ +use std::{sync::mpsc, thread, time::Duration}; + +struct Queue { + first_half: Vec<u32>, + second_half: Vec<u32>, +} + +impl Queue { + fn new() -> Self { + Self { + first_half: vec![1, 2, 3, 4, 5], + second_half: vec![6, 7, 8, 9, 10], + } + } +} + +fn send_tx(q: Queue, tx: mpsc::Sender<u32>) { + // TODO: We want to send `tx` to both threads. But currently, it is moved + // into the first thread. How could you solve this problem? + thread::spawn(move || { + for val in q.first_half { + println!("Sending {val:?}"); + tx.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(); + + send_tx(queue, tx); + + let mut received = Vec::with_capacity(10); + for value in rx { + received.push(value); + } + + received.sort(); + assert_eq!(received, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + } +} |