feat: Adding threads1.rs with a focus on JoinHandles and waiting for

spawned threads to finish. Moved the original threads1.rs to threads2.rs
with the focus on the Mutex and modifying shared data. #892
This commit is contained in:
jaystile 2021-12-23 06:19:39 -08:00 committed by mokou
parent 20024d40c5
commit b4f52cb937
3 changed files with 69 additions and 28 deletions

View File

@ -1,32 +1,31 @@
// threads1.rs // threads1.rs
// Make this compile! Execute `rustlings hint threads1` for hints :) // Make this compile and run! Execute 'rustlings hint threads1' for hints :)
// The idea is the thread spawned on line 22 is completing jobs while the main thread is // This program should wait until all the spawned threads have finished before exiting.
// monitoring progress until 10 jobs are completed. Because of the difference between the
// spawned threads' sleep time, and the waiting threads sleep time, when you see 6 lines
// of "waiting..." and the program ends without timing out when running,
// you've got it :)
// I AM NOT DONE // I AM NOT DONE
use std::sync::Arc;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
struct JobStatus {
jobs_completed: u32,
}
fn main() { fn main() {
let status = Arc::new(JobStatus { jobs_completed: 0 });
let status_shared = status.clone(); let mut handles = vec![];
thread::spawn(move || { for i in 0..10 {
for _ in 0..10 { thread::spawn(move || {
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
status_shared.jobs_completed += 1; println!("thread {} is complete", i);
} });
});
while status.jobs_completed < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
} }
let mut completed_threads = 0;
for handle in handles {
// TODO: a struct is returned from thread::spawn, can you use it?
completed_threads += 1;
}
if completed_threads != 10 {
panic!("Oh no! All the spawned threads did not finish!");
}
} }

View File

@ -0,0 +1,34 @@
// threads2.rs
// Make this compile! Execute `rustlings hint threads2` for hints :)
// 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_completed
// I AM NOT DONE
use std::sync::Arc;
use std::thread;
use std::time::Duration;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(JobStatus { jobs_completed: 0 });
let mut handles = vec![];
for _ in 0..10 {
let status_shared = status.clone();
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_completed += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
// TODO: Print the value of the JobStatus.jobs_completed. Did you notice anything
// interesting in the output? Do you have to 'join' on all the handles?
println!("jobs completed {}", ???);
}
}

View File

@ -878,6 +878,22 @@ name = "threads1"
path = "exercises/threads/threads1.rs" path = "exercises/threads/threads1.rs"
mode = "compile" mode = "compile"
hint = """ hint = """
`JoinHandle` is a struct that is returned from a spawned thread:
https://doc.rust-lang.org/std/thread/fn.spawn.html
A challenge with multi-threaded applications is that the main thread can
finish before the spawned threads are completed.
https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handle
Collect the JoinHandles and wait for them to finish.
https://doc.rust-lang.org/std/thread/struct.JoinHandle.html
"""
[[exercises]]
name = "threads2"
path = "exercises/threads/threads2.rs"
mode = "compile"
hint = """
`Arc` is an Atomic Reference Counted pointer that allows safe, shared access `Arc` is an Atomic Reference Counted pointer that allows safe, shared access
to **immutable** data. But we want to *change* the number of `jobs_completed` to **immutable** data. But we want to *change* the number of `jobs_completed`
so we'll need to also use another type that will only allow one thread to so we'll need to also use another type that will only allow one thread to
@ -898,14 +914,6 @@ while they are sleeping, since this will prevent the other thread from
being allowed to get the lock. Locks are automatically released when being allowed to get the lock. Locks are automatically released when
they go out of scope. they go out of scope.
Ok, so, real talk, this was actually tricky for *me* to do too. And
I could see a lot of different problems you might run into, so at this
point I'm not sure which one you've hit :)
Please open an issue if you're still running into a problem that
these hints are not helping you with, or if you've looked at the sample
answers and don't understand why they work and yours doesn't.
If you've learned from the sample solutions, I encourage you to come If you've learned from the sample solutions, I encourage you to come
back to this exercise and try it again in a few days to reinforce back to this exercise and try it again in a few days to reinforce
what you've learned :)""" what you've learned :)"""