【问题标题】:How to share a pointer to a mutable variable to a thread? [duplicate]如何将指向可变变量的指针共享给线程? [复制]
【发布时间】:2019-04-19 08:25:56
【问题描述】:

我必须为我的国际象棋引擎实现 UCI protocol

它需要从命令行读取命令。当发送go 命令时,必须开始搜索。但是,在此搜索过程中,仍然需要接收其他命令,例如stop。对于stop,搜索必须完全退出。

这就是代码的外观(省略了不重要的细节)。

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
}

此代码不起作用,因为我假设该字段只是被复制了。但是,我尝试提供结构,然后代码抱怨,因为您不能同时拥有可变引用和普通引用。我还研究了与线程通信的方法。然而大多数解决方案都使用通道来实现这一点,但我认为通道在我的情况下不起作用,因为线程总是在计算,所以它只会在它终止后才接收通道的命令。

【问题讨论】:

  • 你想使用 AtomicBool。我建议您在使用线程之前阅读有关 Rust 的更多信息。
  • @FrenchBoiethios 如果我用 AtomicBool 替换我的布尔值,我会收到编译错误:error[E0382]: borrow of moved value: stop` --> src\uci\uci_parser.rs:34:18 | 34 | *stop.get_mut()=false;; | ^^^^ 移动后在这里借用的价值... 42 | thread::spawn(move || { | ------- value 移动到闭包中,在循环的前一次迭代中 | = 注意:move 发生是因为 stop 具有类型 std::sync::atomic::AtomicBool,它没有实现Copy特质`
  • 您需要的不仅仅是 atomicBool。你需要一个弧。这是一个例子(没有睡眠):github.com/Canop/broot/blob/master/src/app.rs#L240你想要答案吗?
  • 你必须使用Arc来获得你的目标

标签: rust thread-safety uci


【解决方案1】:

您需要使用一个特殊的引用,Arc 在线程之间共享布尔值:

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

【讨论】:

  • 感谢这工作。但是我必须将 Arc:.clone(&amp;stop) 移到闭包之外,否则会出现编译器错误
  • @Fabianv.d.W 对。已编辑。
  • 有问题要写吗:stop.clone()?
  • @FrenchBoiethios 是的,请参阅 Arc 的文档:“Arc::clone(&from) 语法是最惯用的,因为它更明确地传达了代码的含义”
  • 另见How can I pass a reference to a stack variable to a thread?;这使您可以完全避免使用Arc
猜你喜欢
  • 2021-08-21
  • 1970-01-01
  • 2022-07-25
  • 1970-01-01
  • 2013-01-21
  • 2013-11-28
  • 2011-10-07
  • 1970-01-01
  • 2015-01-31
相关资源
最近更新 更多