1

I'm trying to map a 2d slice in parallel. I'm doing this by assigning every child slice to one thread. So, if the slice is 10x10, 10 threads will be spawned.

I'm doing this by creating a Mutex for each child slice. The problem is that I'm getting an error for the parent slice:

error[E0759]: `collection` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> src\lib.rs:151:34
    |
145 |     fn gen_map_par<T: Send + Sync, F: Fn(f32, &mut T) + Send + Sync + 'static>(&self, collection: &[&[T]], predicate: F) {
    |                                                                                                   ------- this data with an anonymous lifetime `'_`...
...
151 |         for (x, i) in collection.iter().enumerate() {
    |                                  ^^^^ ...is captured here...
...
155 |             let handle = thread::spawn(move || {
    |                          ------------- ...and is required to live as long as `'static` here

For more information about this error, try `rustc --explain E0759`.

The error shows that collection is being captured. Here is the associated code.

fn gen_map_par<T: Send + Sync, F: Fn(f32, &mut T) + Send + Sync + 'static>(
    &self,
    collection: &[&[T]],
    predicate: F,
) {
    let perm = Arc::new(self.perm);
    let closure = Arc::new(predicate);
    let mut handles = Vec::new();

    for (x, i) in collection.iter().enumerate() {
        // iterating through parent slice
        let p = Arc::clone(&perm);
        let c = Arc::clone(&closure);
        let s = Arc::new(Mutex::new(*i)); // mutex created for one entire child slice
        let handle = thread::spawn(move || {
            // spawning the thread
            let slice = s.lock().unwrap();
            // collection gets moved into the thread for some reason.
            for (y, e) in slice.iter().enumerate() {
                let v = Simplex::convert_range(
                    max_2d,
                    min_2d,
                    1.0,
                    -1.0,
                    generate2d(x as f32, y as f32, &p),
                );
                (c)(v, &mut slice[y]);
            }
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }
}

I've tried wrapping the 'collection' in an arc/mutex, but neither of these works. I'm not sure how to solve this problem. The only solution I've found is to make collection static, but this would require the user to input a static variable, which I do not want to require.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • This is not really fully a duplicate because it also contains the question about why wrapping a reference in an Arc will not work, but you will probably find your answer on any of these: [1](https://stackoverflow.com/questions/32750829/how-can-i-pass-a-reference-to-a-stack-variable-to-a-thread/32751956#32751956) [2](https://stackoverflow.com/questions/57214992/lifetime-issues-in-rust-borrowed-value-does-not-live-long-enough/57215484#57215484) [3](https://stackoverflow.com/questions/71182117/change-elements-in-vector-using-multithreading-in-rust/71182237). – Caesar Apr 11 '22 at 00:37
  • Does this answer your question? [How can I pass a reference to a stack variable to a thread?](https://stackoverflow.com/questions/32750829/how-can-i-pass-a-reference-to-a-stack-variable-to-a-thread) – Chayim Friedman Apr 11 '22 at 02:36
  • @Caesar I do think this is a duplicate since the OP does not show the code that tries to wrap in `Arc`, nor they ask why it didn't work. – Chayim Friedman Apr 11 '22 at 02:37

1 Answers1

-1

After trying crossbeam::scope(), doing some research, and reading @Ceasars' suggestions, I have concluded that using a closure inside of a thread like this is either impossible or very difficult to do because the data has to be moved into the closure as a mutable reference, something the compiler will not allow as far as I can tell. Moving on to another project.

Thanks to everybody who responded, reading your suggestions helped me understand parallelism in rust better.

  • The compiler does allow this kind of thing if you tread carefully. `iter_mut` (or `split_mut` on slices) together with scoped threads. – Caesar Apr 19 '22 at 01:20