0

I use Rayons par_iter()to iterate over different variations of the expensive method I need to run. These runs need to access the same set of checked usizes because they all need to add to it and check it from time to time. I also need them all to shutdown when first thread finishes, this is why I have a kill_switch which will force the iterations to exit when its set to true.

let mut checked: HashSet<usize> = HashSet::new();
let mut kill_switch: bool = false;

permutations.par_iter().for_each(|order| {
    let board = Board::new(board_map.clone(), order.clone());
    let mut bubbles: Vec<(i8, i8)> = Vec::new();
    if let Some(bubbles) = board.solve(&mut bubbles, &mut checked, &kill_switch) {
        kill_switch = true;
        bubbles.into_iter().for_each(|bubble| {
            dbg!(bubble);
        });
    }
})

This is the code I currently have but I get errors for how I'm using checked and kill_switch. How do I make this work?

Errors:

  • cannot borrow checked as mutable, as it is a captured variable in a Fn closure cannot borrow as mutable [E0596]
  • cannot assign to kill_switch, as it is a captured variable in a Fn closure cannot assign [E0594]
MikiS
  • 11
  • 4
  • What you need is a way to sync several threads when they read / write `kill_switch`, because if you do nothing you will have a data race, which Rust tries very hard to prevent (which is why it will not compile, or you will have a runtime error, rather than silently having a data race). The simplest solution, although not with best performance, is a [`Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html). Try wrapping `kill_switch` into one and it should work. To make it shareable among several threads, however, you will probably also need to wrap it in an `Arc`. – jthulhu Jan 09 '23 at 09:21
  • 1
    `kill_switch` is a perfect candidate for `AtomicBool`. The problem with `checked` is trickier, though. – rodrigo Jan 09 '23 at 09:29
  • @rodrigo I cant manage to get AtomicBool working here either. – MikiS Jan 09 '23 at 10:38
  • You should specify your use case if you want a good answer. I saw that the mutex one is slow. Well, it should be slow since you lock it for the duration of `solve` which seems to be the most compute-intensive part of your program. `DashSet` from `dashmap` crate might be a better alternative. But if you want maximum performance we need to know the usage – susitsm Jan 09 '23 at 12:58

1 Answers1

-2

To fix the errors, you will need to use RefCells to wrap the checked and kill_switch variables and use the borrow_mut method to get a mutable reference to them in the closure.

Here is an example of how you can modify your code:

use std::cell::RefCell;
use std::collections::HashSet;

let checked: RefCell<HashSet<usize>> = RefCell::new(HashSet::new());
let kill_switch: RefCell<bool> = RefCell::new(false);

permutations.par_iter().for_each(|order| {
    let board = Board::new(board_map.clone(), order.clone());
    let mut bubbles: Vec<(i8, i8)> = Vec::new();
    if let Some(bubbles) = board.solve(&mut bubbles, &mut checked.borrow_mut(), &mut kill_switch.borrow_mut()) {
        *kill_switch.borrow_mut() = true;
        bubbles.into_iter().for_each(|bubble| {
            dbg!(bubble);
        });
    }
})

Note that you will also need to add RefCell as a dependency in your project.

  • Thank you but your answer causes a big error which I don't quite understand. – MikiS Jan 09 '23 at 09:05
  • `RefCell` doesn't really work in concurrent environments, try replacing `RefCell` with `std::sync::Mutex` and `borrow_mut` with `lock` @MikiS – cafce25 Jan 09 '23 at 09:51
  • @cafce25 I'm afraid I dont yet know how to use Mutexes and Arcs well enough to use them here. – MikiS Jan 09 '23 at 10:39
  • Well then you can't do what you want to I'm afraid. – cafce25 Jan 09 '23 at 10:44
  • I'm afraid that's exactly the reason I'm here asking for help. Why would I ask for it if I knew how to do it already? @cafce25 – MikiS Jan 09 '23 at 11:55
  • I literally told you what I think you need to do. You didn't provide a [mre] so that's all the help I can provide. It's just a string search and replace, no clue where you got lost. – cafce25 Jan 09 '23 at 12:00
  • Thank you, I got it working by simply replacing the things you said, this wasn't exactly clear beforehand. Unfortunately this severely impacts the performance of the code which is unacceptable here. – MikiS Jan 09 '23 at 12:14