【问题标题】:Cannot share Arc variables when spawning threads生成线程时无法共享 Arc 变量
【发布时间】:2020-04-11 20:46:54
【问题描述】:

我有以下结构来表示服务器对象:

pub struct Server {
    client_managers: Arc<ClientManager>,
    listener: Option<TcpListener>,
}

以下是接收客户端连接并在新线程中处理的代码:

fn serve(&self) {
    for stream in self.listener.as_ref().unwrap().incoming() {
        match stream {
            Ok(stream) => {
                let client_manager = &mut self.client_managers.clone();
                // let client_manager = Arc.new(self.client_managers);
                thread::spawn(move || {
                    client_manager.do_something();

                });
            }
            Err(e) => {
                println!("connection error: {}", e);
            }
        }
    }
}

但是,编译时出现以下错误:

error[E0716]: temporary value dropped while borrowed
  --> server/src/server.rs:37:47
   |
37 |                       let client_manager = &mut self.client_managers.clone();
   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
38 |                       // let client_manager = Arc.new(self.client_managers);
39 | /                     thread::spawn(move || {
40 | |                         client_manager.nothing();
41 | |                     });
   | |______________________- argument requires that borrow lasts for `'static`
42 |                   }
   |                   - temporary value is freed at the end of this statement

我明白为什么会发生这个错误。我的问题是:

1) 我通过在线学习一些教程来使用 Arc。 (Example) 但是为什么他们的例子有效而我的无效?

2) 在我的情况下如何解决此错误? (我还是想分享对象client_manager)。

【问题讨论】:

  • 请更新您的问题以包含minimal reproducible example。当我尝试调试这个时,我收到了一堆关于缺少类型的错误消息,而且我不知道如何修复它们,所以我放弃了。但我猜是&amp;mut——为什么会在那里?我只想写let client_manager = self.client_managers.clone(); 这是一个Arc,所以它已经是一个参考;再做一个似乎没有意义。
  • @trentcl 谢谢。您的建议有效,我在更仔细地阅读了 Rust 文档后理解了这一点。我保证下次我会提供可行的代码。

标签: multithreading rust ownership


【解决方案1】:

thread::spawn 采用'static 的闭包,这意味着它不能从线程外部借用数据。但是,此行将克隆 Arc 并借用它,并将借用的引用传递给线程:

let client_manager = &mut self.client_managers.clone();
thread::spawn(move || {
    client_manager.do_something();
//  ^-- client_manager is a `&mut Arc<_>` borrowed from outside the thread
});

相反,你想要的只是克隆Arc,而不是在它传递到线程之前以任何方式借用它:

let client_manager = self.client_managers.clone();
thread::spawn(move || {
    client_manager.do_something();
//  ^-- client_manager is a `Arc<_>` owned by the new thread
});

Arc 共享该值的所有权,因此只有在所有引用它的 Arc 指针超出范围时才会销毁它,即使跨线程也是如此。

【讨论】:

    猜你喜欢
    • 2021-08-14
    • 2018-08-28
    • 2017-09-10
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 2023-03-04
    • 2016-01-06
    • 1970-01-01
    相关资源
    最近更新 更多