Complete exercise: threads_channels

This commit is contained in:
2026-05-26 14:38:45 +04:00
parent 621fb6bb59
commit 76cb232b1e

View File

@@ -22,8 +22,8 @@ fn main() {
// join handle in a variable called `handle`. Once you've done this you should be able to run // join handle in a variable called `handle`. Once you've done this you should be able to run
// the code and see the output from the child thread's expensive sum in the middle of the main // the code and see the output from the child thread's expensive sum in the middle of the main
// thread's processing of letters. // thread's processing of letters.
//
//let handle = ... let handle = thread::spawn(|| expensive_sum(my_vector));
// While the child thread is running, the main thread will also do some work // While the child thread is running, the main thread will also do some work
for letter in vec!["a", "b", "c", "d", "e", "f"] { for letter in vec!["a", "b", "c", "d", "e", "f"] {
@@ -37,63 +37,96 @@ fn main() {
// to a variable named `result` // to a variable named `result`
// - Get the i32 out of `result` and store it in a `sum` variable. // - Get the i32 out of `result` and store it in a `sum` variable.
// let result = let result = handle.join();
// let sum = let sum = result.unwrap();
// println!("The child thread's expensive sum is {}", sum); println!("The child thread's expensive sum is {}", sum);
// 3. Time for some fun with channels! // 3. Time for some fun with channels!
// - Uncomment the block comment below (Find and remove the `/*` and `*/`). // - Uncomment the block comment below (Find and remove the `/*` and `*/`).
// - Create variables `tx` and `rx` and assign them to the sending and receiving ends of an // - Create variables `tx` and `rx` and assign them to the sending and receiving ends of an
// unbounded channel. Hint: An unbounded channel can be created with `channel::unbounded()` // unbounded channel. Hint: An unbounded channel can be created with `channel::unbounded()`
/* let (tx, rx) = channel::unbounded();
// let ...
// Cloning a channel makes another variable connected to that end of the channel so that you can // Cloning a channel makes another variable connected to that end of the channel so that you can
// send it to another thread. We want another variable that can be used for sending... // send it to another thread. We want another variable that can be used for sending...
let tx2 = tx.clone(); let tx2 = tx.clone();
// 4. Examine the flow of execution of "Thread A" and "Thread B" below. Do you see how their // 4. Examine the flow of execution of "Thread A" and "Thread B" below. Do you see how their
// output will mix with each other? // output will mix with each other?
// - Run this code. Notice the order of output from Thread A and Thread B. // - Run this code. Notice the order of output from Thread A and Thread B.
// - Increase the value passed to the first `sleep_ms()` call in Thread A so that both the // - Increase the value passed to the first `sleep_ms()` call in Thread A so that both the
// Thread B outputs occur *before* Thread A outputs anything. // Thread B outputs occur *before* Thread A outputs anything.
// - Run the code again and make sure the output comes in a different order. // - Run the code again and make sure the output comes in a different order.
// Thread A // Thread A
let handle_a = thread::spawn(move || { let handle_a = thread::spawn(move || {
sleep_ms(0); sleep_ms(500);
tx2.send("Thread A: 1").unwrap(); tx2.send("Thread A: 1").unwrap();
sleep_ms(200); sleep_ms(200);
tx2.send("Thread A: 2").unwrap(); tx2.send("Thread A: 2").unwrap();
}); });
sleep_ms(100); // Make sure Thread A has time to get going before we spawn Thread B sleep_ms(100); // Make sure Thread A has time to get going before we spawn Thread B
// Thread B // Thread B
let handle_b = thread::spawn(move || { let handle_b = thread::spawn(move || {
sleep_ms(0); sleep_ms(0);
tx.send("Thread B: 1").unwrap(); tx.send("Thread B: 1").unwrap();
sleep_ms(200); sleep_ms(200);
tx.send("Thread B: 2").unwrap(); tx.send("Thread B: 2").unwrap();
}); });
// Using a Receiver channel as an iterator is a convenient way to get values until the channel // Using a Receiver channel as an iterator is a convenient way to get values until the channel
// gets closed. A Receiver channel is automatically closed once all Sender channels have been // gets closed. A Receiver channel is automatically closed once all Sender channels have been
// closed. Both our threads automatically close their Sender channels when they exit and the // closed. Both our threads automatically close their Sender channels when they exit and the
// destructors for the channels get automatically called. // destructors for the channels get automatically called.
for msg in rx { for msg in rx {
println!("Main thread: Received {}", msg); println!("Main thread: Received {}", msg);
} }
// 5. Oops, we forgot to join "Thread A" and "Thread B". That's bad hygiene! // 5. Oops, we forgot to join "Thread A" and "Thread B". That's bad hygiene!
// - Use the thread handles to join both threads without getting any compiler warnings. // - Use the thread handles to join both threads without getting any compiler warnings.
*/ let _ = handle_a.join();
let _ = handle_b.join();
// Challenge: Make two child threads and give them each a receiving end to a channel. From the // Challenge: Make two child threads and give them each a receiving end to a channel. From the
// main thread loop through several values and print each out and then send it to the channel. // main thread loop through several values and print each out and then send it to the channel.
// On the child threads print out the values you receive. Close the sending side in the main // On the child threads print out the values you receive. Close the sending side in the main
// thread by calling `drop(tx)` (assuming you named your sender channel variable `tx`). Join // thread by calling `drop(tx)` (assuming you named your sender channel variable `tx`). Join
// the child threads. // the child threads.
let (tx, rx) = channel::unbounded();
let rx2 = rx.clone();
let thread_a_handle = thread::spawn(move || {
for n in rx {
println!("Thread A received: {}", n);
sleep_ms(10);
}
});
let thread_b_handle = thread::spawn(move || {
for n in rx2 {
println!("Thread B received: {}", n);
sleep_ms(10);
}
});
for number in vec![
1,
2,
3,
4,
5,
] {
println!("NUMBER: {}", number);
let _ = tx.send(number);
}
drop(tx);
let _ = thread_a_handle.join();
let _ = thread_b_handle.join();
println!("Main thread: Exiting.") println!("Main thread: Exiting.")
} }