3

I have to implement the UCI protocol for my chess engine.

It requires to read commands from command line. When the go command is sent, a search has to be started. However, during this search, other commands such as stop still have to be received. In the case of stop, the search has to quit altogether.

This is how the code looks (with leaving out non-important details).

pub fn main() {
    let mut stop: bool = false;
    loop {
        line.clear();
        stdin.read_line(&mut line).ok().unwrap();
        let arg: Vec<&str> = line.split_whitespace().collect();
        let cmd = arg[0];
        match cmd.trim() {
            "" => continue,
            "go" => {
                stop = false;
                thread::spawn(move || start_search(&stop, GameState, History, Timecontrol));
            }
            "stop" => {
                stop = true;
                thread::sleep(Duration::from_millis(50));
            }
            "quit" => {
                stop = true;
                thread::sleep(Duration::from_millis(50));
                break;
            }
            _ => {
                println!("Unknown command {}", line);
            }
        }
    }
}

pub fn start_search(stop_reference: &bool, _: GameState, _: History, _: Timecontrol) {
    /* Do search stuff here...
     */
    //Has to break when stop_reference is set to true
}

This code doesn't work because I assume the field just get's copied. However I have tried giving structs and then the code complains because you can't have a mutable reference and a normal reference both at once. I have also looked into ways to communicate with a thread. However most of the solutions used a channel to achieve that, but I think a channel doesn't work in my case since the thread is always calculating, so it would only receive the channels' command after it has terminated anyway.

Stargateur
  • 24,473
  • 8
  • 65
  • 91
Fabian v.d.W
  • 155
  • 12
  • 2
    You want to use AtomicBool. I advice you to read more about Rust before playing with threads. – Boiethios Apr 19 '19 at 08:30
  • @FrenchBoiethios If I replace my bools with AtomicBool , I get the compile error: `error[E0382]: borrow of moved value: `stop` --> src\uci\uci_parser.rs:34:18 | 34 | *stop.get_mut()=false;; | ^^^^ value borrowed here after move ... 42 | thread::spawn(move || { | ------- value moved into closure here, in pre vious iteration of loop | = note: move occurs because `stop` has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait` – Fabian v.d.W Apr 19 '19 at 08:37
  • You need a little more than an atomicBool. You need an Arc. Here's an example (without sleep): https://github.com/Canop/broot/blob/master/src/app.rs#L240 Do you want an answer for that? – Denys Séguret Apr 19 '19 at 08:39
  • You have to use `Arc` to obtain your goal – sn99 Apr 19 '19 at 08:42

1 Answers1

3

You'll need to use a special reference, an Arc to share the boolean value between threads:

pub fn main() {
    let stop = Arc::new(AtomicBool::new(false));
    loop {
        //...

        let stop = Arc::clone(&stop);
        thread::spawn(move || {
            start_search(stop);
        })
    }
}
pub fn start_search(stop: Arc<AtomicBool>) {
    loop {
        if stop.load(Ordering::Relaxed) {
            // STOP
        }
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758