record progress: threads
This commit is contained in:
parent
1119249fa1
commit
13f58c87bd
7 changed files with 150 additions and 21 deletions
|
@ -1,6 +1,6 @@
|
||||||
DON'T EDIT THIS FILE!
|
DON'T EDIT THIS FILE!
|
||||||
|
|
||||||
threads1
|
macros1
|
||||||
|
|
||||||
intro1
|
intro1
|
||||||
intro2
|
intro2
|
||||||
|
@ -80,4 +80,7 @@ iterators5
|
||||||
box1
|
box1
|
||||||
rc1
|
rc1
|
||||||
arc1
|
arc1
|
||||||
cow1
|
cow1
|
||||||
|
threads1
|
||||||
|
threads2
|
||||||
|
threads3
|
|
@ -22,8 +22,8 @@ fn main() {
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
for handle in handles {
|
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`.
|
// Use the `JoinHandle` struct which is returned by `thread::spawn`.
|
||||||
|
results.push(handle.join().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
if results.len() != 10 {
|
if results.len() != 10 {
|
||||||
|
|
|
@ -3,23 +3,21 @@
|
||||||
// shared value: `JobStatus.jobs_done`
|
// shared value: `JobStatus.jobs_done`
|
||||||
|
|
||||||
use std::{sync::Arc, thread, time::Duration};
|
use std::{sync::Arc, thread, time::Duration};
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
struct JobStatus {
|
struct JobStatus {
|
||||||
jobs_done: u32,
|
jobs_done: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// TODO: `Arc` isn't enough if you want a **mutable** shared state.
|
let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
|
||||||
let status = Arc::new(JobStatus { jobs_done: 0 });
|
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
let status_shared = Arc::clone(&status);
|
let mut status_shared = Arc::clone(&status);
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
thread::sleep(Duration::from_millis(250));
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
status_shared.lock().unwrap().jobs_done += 1;
|
||||||
// TODO: You must take an action before you update a shared value.
|
|
||||||
status_shared.jobs_done += 1;
|
|
||||||
});
|
});
|
||||||
handles.push(handle);
|
handles.push(handle);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +27,5 @@ fn main() {
|
||||||
handle.join().unwrap();
|
handle.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Print the value of `JobStatus.jobs_done`.
|
println!("Jobs done: {}", status.lock().unwrap().jobs_done);
|
||||||
println!("Jobs done: {}", todo!());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,9 @@ impl Queue {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
|
fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
|
||||||
// TODO: We want to send `tx` to both threads. But currently, it is moved
|
// We want to send `tx` to both threads. But currently, it is moved
|
||||||
// into the first thread. How could you solve this problem?
|
// into the first thread. How could you solve this problem?
|
||||||
|
let tx2 = tx.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
for val in q.first_half {
|
for val in q.first_half {
|
||||||
println!("Sending {val:?}");
|
println!("Sending {val:?}");
|
||||||
|
@ -28,7 +29,7 @@ fn send_tx(q: Queue, tx: mpsc::Sender<u32>) {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
for val in q.second_half {
|
for val in q.second_half {
|
||||||
println!("Sending {val:?}");
|
println!("Sending {val:?}");
|
||||||
tx.send(val).unwrap();
|
tx2.send(val).unwrap();
|
||||||
thread::sleep(Duration::from_millis(250));
|
thread::sleep(Duration::from_millis(250));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,37 @@
|
||||||
|
// This program spawns multiple threads that each run for at least 250ms, and
|
||||||
|
// each thread returns how much time they 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() {
|
fn main() {
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
let mut handles = Vec::new();
|
||||||
// It will be automatically filled after you finish the exercise.
|
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 {
|
||||||
|
// Collect the results of all threads into the `results` vector.
|
||||||
|
results.push(handle.join().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,41 @@
|
||||||
fn main() {
|
// Building on the last exercise, we want all of the threads to complete their
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// work. But this time, the spawned threads need to be in charge of updating a
|
||||||
// It will be automatically filled after you finish the exercise.
|
// shared value: `JobStatus.jobs_done`
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JobStatus {
|
||||||
|
jobs_done: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// `Arc` isn't enough if you want a **mutable** shared state.
|
||||||
|
// We need to wrap the value with a `Mutex`.
|
||||||
|
let status = Arc::new(Mutex::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));
|
||||||
|
|
||||||
|
// Lock before you update a shared value.
|
||||||
|
status_shared.lock().unwrap().jobs_done += 1;
|
||||||
|
// ^^^^^^^^^^^^^^^^
|
||||||
|
});
|
||||||
|
handles.push(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waiting for all jobs to complete.
|
||||||
|
for handle in handles {
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Jobs done: {}", status.lock().unwrap().jobs_done);
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,62 @@
|
||||||
fn main() {
|
use std::{sync::mpsc, thread, time::Duration};
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
|
||||||
// It will be automatically filled after you finish the exercise.
|
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>) {
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue