Return ownership from closure move after thread finished

I am learning Rust and am now taking a look at threads. I am trying to convert the following snippet into a parallelized execution:

fn main() {
	let mut data: Vec<usize> = (1..22).collect();

	for d in &mut data {
		*d *= 99;
	}
}

Since the processing of each element is completely independent from the others, this should be easy to parallelize. So I wrote the following code which splits the vector into N_THREADS parts and then gives each part to a thread to do the processing:

use std::thread;

const N_THREADS: usize = 8;
const N_ELEMENTS: usize = 2*N_THREADS;

fn main() {
	let mut data: Vec<usize> = (1..N_ELEMENTS).collect();

	let mut threads = vec![];
    for n_thread in 0..N_THREADS {
		let thread_fn = move || {
            for d in &mut data[n_thread*(N_ELEMENTS/N_THREADS)..(n_thread+1)*(N_ELEMENTS/N_THREADS)] {
                *d *= 99
            }
        };
        let thread_handle = thread::spawn(thread_fn);
        threads.push(thread_handle);
    }
	// Now wait for the threads to finish.
    for t in threads {
        t.join().unwrap();
    } // I need each `t` to return the ownership of its respective piece of `data` here!
    
    do_something_else(data);
}

How can I get the ownership of data back after all the threads have finished, so then I can do_something_else(data)?

The standard library thread API doesn't have an easy way to do work in parallel on an array like that. However, the rayon crate can do it:

use rayon::prelude::*;

fn main() {
	let mut data: Vec<usize> = (1..22).collect();

    data.par_iter_mut().for_each(|d| {
        *d *= 99;
    });
    
    println!("{:?}", data);
}
[99, 198, 297, 396, 495, 594, 693, 792, 891, 990, 1089, 1188, 1287, 1386, 1485, 1584, 1683, 1782, 1881, 1980, 2079]

This will run in parallel due to the use of par_iter_mut.

2 Likes

You can use chunks_exact_mut to split the borrows of the various chunks and std::thread::scope to process them in parallel without having to move the ownership of the vec into the closure

const N_THREADS: usize = 8;
const N_ELEMENTS: usize = 2 * N_THREADS;

fn main() {
    let mut data: Vec<usize> = (1..N_ELEMENTS).collect();

    let mut threads = vec![];
    std::thread::scope(|s| {
        for chunk in data.chunks_exact_mut(N_ELEMENTS / N_THREADS) {
            s.spawn(|| {
                for d in chunk {
                    *d *= 99;
                }
            });
        }
    });

    do_something_else(data);
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.