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.
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
}
}
}