We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Fearless Concurrency: Threads, Channels, Shared State step 9 of 24
Arc: shared ownership across threads
Fix the starter so worker threads share the input through Arc<Vec<i64>>. Each worker sums a disjoint slice. Join every thread, add its result to the total, and return the total together with the remaining strong-reference count.
pub fn share_and_reduce(data: Vec<i64>, workers: usize) -> (i64, usize)
Use thread::spawn and give each worker its own cloned Arc handle. Keep the original handle in the calling thread so you can read Arc::strong_count(&shared) after joining. Use this ownership pattern rather than scoped borrowing for this exercise.
Split the input evenly
Treat workers == 0 as 1. For the adjusted count, calculate:
base = data.len() / workersextra = data.len() % workers
Give the first extra workers base + 1 elements each, and the rest base elements each. Assign consecutive slices without overlap or gaps.
For [1, 2, 3, 4, 5] and three workers, the slices are [1, 2], [3, 4], and [5]. The result is (15, 1). If there are more workers than elements, some slices are empty and contribute zero. Empty input returns (0, 1).
Worker counts are small enough to spawn the requested threads. All intermediate chunk sums and total additions fit in i64; integer overflow and thread-creation failure recovery are outside this exercise.
Move a new handle into each worker
The starter moves shared itself into a closure, then tries to use it again. Rust reports E0382 because Arc handles are not Copy.
Clone the handle before creating each closure. A small example:
use std::sync::Arc;
use std::thread;
fn main() {
let shared = Arc::new(vec![2_i64, 3]);
let mine = Arc::clone(&shared);
let worker = thread::spawn(move || mine.iter().sum::<i64>());
assert_eq!(worker.join().expect("worker thread panicked"), 5);
assert_eq!(Arc::strong_count(&shared), 1);
}
The closure owns mine, so it can use the data without borrowing the local shared variable. The calling thread still owns shared.
These threads are joined, not detached. Dropping a JoinHandle without joining detaches its thread; simply calling thread::spawn does not mean you have chosen to detach it.
What cloning shares
Arc::clone(&shared) creates another handle to the same allocation and updates the atomic reference count. It does not clone the contained vector or copy its elements. shared.clone() has the same behavior here; the explicit form makes the operation easy to recognize.
Moving a Vec into Arc::new creates an allocation for the Arc's bookkeeping and the vector value. The vector retains its existing element buffer. Cloning the Arc shares access to that buffer rather than allocating a buffer per worker. Thread stacks and the vector of join handles still use memory, so this is not an allocation-free computation.
Arc<T> supports cross-thread ownership when the required Send and Sync bounds on T hold. Atomic reference counting does not make arbitrary mutation of T safe. This exercise only reads the shared elements.
Why the final count is one
Each worker drops its cloned handle when its closure finishes. Here, workers return only their sums and do not store or pass their handles elsewhere. After every successful join, the original handle is the only strong reference left. Read the count then, rather than returning a hard-coded value.
A concurrent strong_count read is safe, but its result is only a snapshot. Another thread can clone or drop a handle before you act on that number. That is a timing concern, not an unsynchronized data race inside Arc. Do not use a count read as permission to mutate shared data; APIs such as Arc::get_mut perform the necessary uniqueness check.
Joining threads does not universally imply a count of one. Extra handles retained by the caller or returned by workers would also count. The result is one because of this exercise's ownership pattern.
When the last strong handle is dropped, the contained value is dropped. Weak pointers, if any, can keep the backing allocation alive without keeping that value alive.
Two cloning lints
clippy::clone_on_ref_ptr can require the explicit Arc::clone style, but it is an optional restriction lint. It is not enabled by -D warnings alone.
The default warning clippy::rc_clone_in_vec_init catches a different pattern: vec![Arc::new(data); count]. This repetition constructs one Arc, then clones handles to it; it does not construct independent vectors. That sharing is intentional in this exercise, so bind the Arc first and clone from the binding, as the starter's loop requires. Under -D warnings, an enabled Clippy warning fails the gate.
Further reading: Arc and reference counts, JoinHandle::join, and the repeated-Arc initialization lint.
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.