How to use std::slice::Chunks on Arc<Mutex<Vec<u8>>> properly between threads in Rust?

Viewed 735

i'd like to gain understanding why following seems to not work properly in Rust.

I'd like to chunk a vector and give every thread a chunk to work on it. I tried it with a Arc and a Mutex combination to have mutual access to my vec.

This was my first (obvious) attempt: Declare the vec, chunk it, send chunk into each thread. In my understanding it should work because the Chunk methods guarantees non overlapping chunks.

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new(vec![0;20]));
    let chunk_size = 5;
    let mut threads = vec![];
    let chunks: Vec<&mut [u8]> = data.lock().unwrap().chunks_mut(chunk_size).collect();

    for chunk in chunks.into_iter(){
        threads.push(thread::spawn(move || {
                inside_thread(chunk)
            }));
    }

}
fn inside_thread(chunk: &mut [u8]) {
    // now do something with chunk
}

The error says data does not live enough. Silly me, with the chunking i created pointers to the array but passed no Arc reference into the thread. So i changed a few lines, but it would make no sense because I'd have an unused reference in my thread!?

for i in 0..data.lock().unwrap().len() / 5 {
        let ref_to_data = data.clone();
        threads.push(thread::spawn(move || {
                inside_thread(chunk, ref_to_data)
            }));
    }

The error still says that data does not live enough.

The next attempt didn't work either. I thought ok i could work around it and chunk it inside the thread and get my chunk by an index. But if it worked the code wouldn't be very rust idiomatic :/

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new(vec![0;20]));
    let chunk_size = 5;
    let mut threads = vec![];

    for i in 0..data.lock().unwrap().len() / chunk_size {
        let ref_to_data = data.clone();
        threads.push(thread::spawn(move || {
                inside_thread(ref_to_data, i, chunk_size)
            }));
    }

}
fn inside_thread(data: Arc<Mutex<Vec<u8>>>, index: usize, chunk_size: usize) {
    let chunk: &mut [u8] = data.lock().unwrap().chunks_mut(chunk_size).collect()[index];
    // now do something with chunk
}

The error says:

--> src/main.rs:18:72
   |
18 |     let chunk: &mut [u8] = data.lock().unwrap().chunks_mut(chunk_size).collect()[index];
   |                                                                        ^^^^^^^
   |                                                                        |
   |                                                                        cannot infer type for type parameter `B` declared on the method `collect`
   |                                                                        help: consider specifying the type argument in the method call: `collect::<B>`
   |
   = note: type must be known at this point

And when i try to infer it it doesn't work either. So for now i tried much and nothing worked and im out of ideas. Ok what i always could do is to "do the chunking on my own". Just mutating the vector inside the threads works fine. But this is no idiomatic nice way to do it (in my opinion).

Question: Is there a possible way to solve this problem rust idiomatic?

Hint: I know i could work with an scoped-threadpool or something like this but i want to gain this knowledge for my thesis.

Much thanks for spending your time on this!

0 Answers
Related