Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Rust crossbeam borrow mutable in a loop

I try to process an array with multiple worker threads, just like Rayon’s par_iter() function, but i want to have a mutable reference target, one for each thread.

I have a simple function like this


pub fn parallel_map_vector<A:Sync,T:Send,B:Send>(a:&[A], t:&mut [T], b:&mut [B], f:impl Fn(&A,&mut T)+Send+Sync){
    assert_eq!(a.len(),b.len());
    let atomic_counter = AtomicUsize::new(0);
    crossbeam::scope(|scope| {
        for target in t {
            scope.spawn( |_| {
                loop {
                    let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
                    if idx < a.len() {unsafe{std::slice::from_raw_parts_mut(b,b_len)};
                        f(&a[idx], target)
                    }else{
                        break
                    }
                }
            });
        }
    }).unwrap();
}

For some reason i keep getting the error

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

error[E0373]: closure may outlive the current function, but it borrows `target`, which is owned by the current function
  --> htm/src/parallel.rs:11:26
   |
9  |     crossbeam::scope(|scope| {
   |                       ----- has type `&crossbeam::thread::Scope<'1>`
10 |         for target in t {
11 |             scope.spawn( |_| {
   |                          ^^^ may outlive borrowed value `target`
...
17 |                         f(&a[idx], target)
   |                                    ------ `target` is borrowed here
   |
note: function requires argument type to outlive `'1`
  --> htm/src/parallel.rs:11:13
   |
11 | /             scope.spawn( |_| {
12 | |                 loop {
13 | |                     let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
14 | |                     if idx < a.len() {
...  |
21 | |                 }
22 | |             });
   | |______________^
help: to force the closure to take ownership of `target` (and any other referenced variables), use the `move` keyword
   |
11 |             scope.spawn( move |_| {

but when i try it in rust playground it compiles without problem
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0a10cbfd2f135975f4682c843664d539
What could be wrong here? The code looks safe to me.

>Solution :

The playground example to which you have linked is using the 2021 edition of Rust, which allows disjoint capture in closures (and hence the closure for each thread captures only target rather than the entire t slice). If you switch to the 2018 edition, it yields the same error as in your question.

Specify that you require the 2021 edition in your Cargo.toml (requires rustc >= 1.56.0).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading