国际象棋引擎 Rust 中的线程不运行线程内的代码

问题描述 投票:0回答:1

我正在尝试使用 Rust 编写一个国际象棋引擎,我希望它能够启动一个线程,以便它可以在思考时监听 uci 命令。这是我的代码的简化版本,它按预期工作,将停止标志和句柄传递给主线程,以便主线程可以停止 ai 线程,然后加入它。


    #[test]
    fn start_thread() {
        let test_struct = TestStruct { stop_flag: None, test_data: String::from("not modified") };
        println!("{}", test_struct.test_data);
        let x = test_struct.start_thread();
        thread::sleep(Duration::from_secs(1));
        let test_struct = x.stop();
        println!("{}", test_struct.test_data);
    }

    pub struct ThreadInfo {
        stop_flag: Arc<AtomicBool>,
        join_handle: JoinHandle<TestStruct>,
    }

    impl ThreadInfo {
        pub fn stop(self) -> TestStruct {
            println!("stopping");
            self.stop_flag.store(true, Ordering::SeqCst);
            println!("stop flag main thread: {}", self.stop_flag.load(Ordering::Relaxed));
            let mut ai = self.join_handle.join().expect("failed to join thread");
            ai.stop_flag = None;
            println!("stopped");
            ai
        }
    }

    struct TestStruct {
        stop_flag: Option<Arc<AtomicBool>>,
        test_data: String,
    }

    impl TestStruct {
        pub fn start_thread(mut self) -> ThreadInfo {
            let stop_flag = Arc::new(AtomicBool::new(false));
            let stop_flag_clone = Arc::clone(&stop_flag);
            self.stop_flag = Some(stop_flag_clone);

            println!("starting");

            let handle = thread::spawn(move || {
                println!("thread start");
                loop {
                    println!("thread running");
                    //let start_time = Instant::now();
                    //let evaluation = self.negamax(&self.game.deep_clone(), depth, 0, -INFINITY, INFINITY);
                    //let pv_string = self.reconstruct_principal_variation();
                    if let Some(stop_flag) = &self.stop_flag {
                        if stop_flag.load(Ordering::Relaxed) { break; }
                    }
                    self.test_data = String::from("modified");
                    //let depth_duration = start_time.elapsed();
                    //Self::uci_print_evaluation_info(evaluation, depth, depth_duration, pv_string);
                    //self.uninterupted_best_move = Some(self.last_principal_variation[0]);
                }
                self
            });

            println!("started {:?}", handle);

            ThreadInfo {
                stop_flag: stop_flag,
                join_handle: handle,
            }
        }
    }

问题是,这是我的引擎中实际代码的简化版本,并且不起作用。我惊慌失措!在线程的第一行声明,只是为了看看它是否正在运行线程内部的代码,并且它不会panic。当我对简化代码执行此操作时,它确实出现恐慌并产生错误消息。停止标志实际上并没有停止线程,并且它永远不会加入。我看不出我的代码与上面有效的测试代码有何不同。以下是我的代码的相关部分:

pub struct ThreadInfo {
    stop_flag: Arc<AtomicBool>,
    join_handle: JoinHandle<AI>,
}

impl ThreadInfo {
    pub fn stop(self) -> AI {
        println!("stopping");
        self.stop_flag.store(true, Ordering::SeqCst);
        println!("stop flag main thread: {}", self.stop_flag.load(Ordering::Relaxed));
        let mut ai = self.join_handle.join().expect("failed to join thread");
        ai.stop_flag = None;
        println!("stopped");
        ai
    }
}


pub struct AI {
    move_data: AllMoveData,
    hashes: Hashes,
    game: Game,
    name: String,
    transposition_table: TranspositionTable,
    last_principal_variation: Vec<EncodedMove>,
    stop_flag: Option<Arc<AtomicBool>>,
    uninterupted_best_move: Option<EncodedMove>,
}
impl AI {
    pub fn start_thread(mut self) -> ThreadInfo {
        let stop_flag = Arc::new(AtomicBool::new(false));
        let stop_flag_clone = Arc::clone(&stop_flag);
        self.stop_flag = Some(stop_flag_clone);

        println!("starting");

        let handle = thread::spawn(move || {
            println!("thread start");
            panic!("thread started! yay!");
            for depth in 1..MAX_DEPTH {
                let start_time = Instant::now();
                let evaluation = self.negamax(&self.game.deep_clone(), depth, 0, -INFINITY, INFINITY);
                let pv_string = self.reconstruct_principal_variation();
                if self.check_stop_flag() { break; }
                let depth_duration = start_time.elapsed();
                Self::uci_print_evaluation_info(evaluation, depth, depth_duration, pv_string);
                self.uninterupted_best_move = Some(self.last_principal_variation[0]);
            }
            self
        });

        println!("started {:?}", handle);

        ThreadInfo {
            stop_flag: stop_flag,
            join_handle: handle,
        }
    }

    fn check_stop_flag(&self) -> bool {
        if let Some(stop_flag) = &self.stop_flag {
            return stop_flag.load(Ordering::Relaxed);
        }
        false
    }
}

这是 main.rs 中调用此代码的部分:

                
                    let ai_thread = ai.start_thread();
                    thread::sleep(Duration::from_millis(move_time));
                    ai = ai_thread.stop();
                    writeln!(handle, "bestmove {}", ai.get_best_move()).unwrap();
                

negamax 和 quiescent 函数在函数开始处和循环内调用 check_stop_flag,因此它只返回 0 并使用上次完成的搜索的结果。当我以 1000 毫秒运行 main 函数时,它确实在打印“开始”和“停止”之间等待一秒钟,但它永远不会“停止”,也永远不会打印移动。它似乎甚至没有尝试运行线程内的任何代码。是什么让我的代码不像简化版本那样表现?

multithreading rust
1个回答
0
投票

原来问题是println!声明。它们在测试函数的线程中工作得很好,但在 ai 线程中放置一个 printline 函数,它就会冻结。我的引擎在搜索时不再打印信息,但它现在可以运行并且可以提供上次搜索的信息。

© www.soinside.com 2019 - 2024. All rights reserved.