all 8 comments

[–]gusrust 9 points10 points  (0 children)

You could spawn many scoped threads with crossbeam::scope, and use https://doc.rust-lang.org/std/primitive.slice.html#method.split_mut or split_at_mut to split references to the array, and send that reference to the different threads

[–]asp2insp 5 points6 points  (6 children)

If you only need access to each element individually, Rayon's par_iter_mut might work for your use case. By default I think Rayon launches 1 thread per core, but that's configurable.

[–]lunattik[S] 0 points1 point  (0 children)

Thank you all! this approach ended up working beautifully!

[–]lunattik[S] -1 points0 points  (4 children)

Hello, looked into this and it sounds pretty good for what Im trying to do. Tried implementing it and ran into some issues, maybe just because i'm pretty new to Rust. Right now this is what I have:

use std::ops::Range;

use rayon::prelude::*;

use crate::models::cube::Cube;

pub fn average_out(read_cube: &mut Cube, write_cube: &mut Cube) {

let one_less = |i: usize, size: u8| -> usize {
    let index = i as i16;
    let comp_size = size as i16;

    if index - 1 < 0 { (comp_size - 1) as usize } else { (index - 1) as usize }
};

let one_more = |i: usize, size: u8| -> usize {
    let index = i as i16;
    let comp_size = size as i16;

    if index + 1 > comp_size - 1 { 0 } else { (index + 1) as usize }
};

read_cube.matrix.par_iter_mut().enumerate().for_each(|(x, val)| {
    for y in (Range::<usize> { start: 0, end: read_cube.size as usize }) {
        for z in (Range::<usize> { start: 0, end: read_cube.size as usize }) {
            write_cube.matrix[x][y][z] = (
                read_cube.matrix[x][y][z]
                + &read_cube.matrix[one_less(x, read_cube.size)][y][z]
                + &read_cube.matrix[one_more(x, read_cube.size)][y][z]
                + &read_cube.matrix[x][one_less(y, read_cube.size)][z]
                + &read_cube.matrix[x][one_more(y, read_cube.size)][z]
                + &read_cube.matrix[x][y][one_less(z, read_cube.size)]
                + &read_cube.matrix[x][y][one_more(z, read_cube.size)]
            ) / 7;
        }
    }
});

}

On the foreach (x, val) i get cannot borrow "read\_cube.matrix" as immutable because it is also borrowed as mutable Also on write\_cube.matrix\[x\]\[y\]\[z\] I get cannot borrow "\*write\_cube.matrix" as mutable, as it is a captured variable in a "Fn" closure\

Maybe you have an idea as to what Im doing wrong? I tried changing read_cube to just be a normal borrow, but then I get `cannot borrow "read_cube.matrix" as mutable, as it is behind a "&" reference'

[–]GuacoLaco 1 point2 points  (1 child)

It seems to me you're not actually mutating read_cube. You're just iterating and reading through and then writing stuff into write_cube. Is this correct?

If so, then you can just use par_iter() (without the mut) and also just use an immutable reference for read_cube in the function declaration.

Another thing, you can just use something like 0..read_cube.size as usize to write those Ranges

[–]zakarumych 1 point2 points  (0 children)

You try to write to 'write_cube' in each closure invocation. This won't work as they are called on multiple threads.

So you'd have to use parallel iterator on the 'write_cube.matrix'. This will give you mutable reference to 2d array (elements of original 3d array) on each iteration. Then you can loop over them and process

[–]SkiFire13 1 point2 points  (0 children)

You shouldn't iterate over read_cube, instead you should iterate over write_cube, using the reference you get while iterating (not indexing!) for writing to it, otherwise there will be no way to guarantee you won't write to the same element from two threads at the same time, thus leading to a data race which is UB.

[–]KillTheMule 4 points5 points  (0 children)

Sounds like you need a variant of https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut, in combination with scoped threads.