We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Fearless Concurrency: Threads, Channels, Shared State step 17 of 24
Let a channel receiver finish by dropping its senders
Fix the starter's channel shutdown so it returns every squared input value,
sorted in ascending order. Keep the supplied worker setup, joins and receiver
loop, including for x in rx. Do not replace it with a counted receive loop.
pub fn drain_all(values: Vec<i64>, workers: usize) -> Vec<i64>
Preserve duplicates. For [1, -2, 3], return [1, 4, 9]; for
[-3, -3, 2, 2], return [4, 4, 9, 9]. Empty input returns an empty vector.
Treat workers equal to zero as one. Worker counts are nonnegative and fit usize.
The supplied code divides values into chunks and starts one thread per chunk, so it can use fewer threads than requested. Empty input starts none. Scheduling may change message arrival order; the final sort makes the result deterministic.
Inputs are i64 values. With the runner's current optimized execution settings, an overflowing square wraps in 64 bits and the wrapped signed results are sorted. For example, i64::MAX squares to 1 and i64::MIN squares to 0. Values from -3037000499 through 3037000499 square without overflow. In a checked build, an overflowing worker multiplication instead panics, and its failed join makes this function panic. Build settings matter independently of the channel repair.
Why the receiver waits
This starter compiles and passes Clippy, but its parent thread retains the original sender while waiting for the receiver loop to finish. Worker threads own cloned senders, which are dropped when those threads finish.
The receiver can deliver all queued messages and still wait for another one. It cannot know that the parent will never send: the original tx is still alive. The parent cannot reach the end of the function to drop tx because it is waiting inside the receiver loop. This also affects empty input, where the original tx is the only sender and no messages are produced.
The blocking receiver iterator finishes once both conditions hold:
- All sender handles have been dropped.
- All messages already queued have been received.
Dropping the last sender does not discard buffered messages. This complete example demonstrates that behavior without needing a worker thread:
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
tx.send(10).unwrap();
tx.send(20).unwrap();
drop(tx);
assert_eq!(rx.recv(), Ok(10));
assert_eq!(rx.recv(), Ok(20));
assert!(rx.recv().is_err());
}
See the receiver documentation for blocking and disconnection behavior.
Release the parent's sender before receiving
Add drop(tx); after the worker-spawn loop and before for x in rx.
Each worker retains its own sender, so it can still send results. Once all
workers finish, no senders remain. The receiver drains any remaining messages
and the loop ends. For empty input, dropping the original sender lets the
loop end immediately.
Keep the join loop: completion of channel iteration is not a substitute for checking thread results. The supplied joins expose worker panics.
An extra sender clone retained across the receiver loop would recreate the wait. This includes handles stored inside another object. Keeping a sender is appropriate while more work may arrive, but this finite task needs to release the parent's handle before waiting for disconnection.
Other designs can use a tighter sender scope or transfer the original handle into a worker. Such designs must handle the no-worker case too. The explicit drop is the small repair needed here.
Sender and receiver lifetimes both matter
Dropping the receiver has a different effect: later sends fail. The standard mpsc channel uses endpoint ownership for these transitions; that does not mean sends can never fail or that every channel library has the same API.
A timeout alone does not prove where a program is blocked. For this starter, trace the original sender through the receiver loop. In a different program, also consider worker failures, other locks and work that has not finished. Clippy cannot prove that an otherwise valid channel program will terminate.
Passing requires correct output, compilation and Clippy with warnings treated as errors.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.