【问题标题】:Lifetime of variables passed to a new thread传递给新线程的变量的生命周期
【发布时间】:2015-12-23 16:29:55
【问题描述】:

我无法编译这个程序:

use std::env;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let args: Vec<_> = env::args().skip(1).collect();

    let (tx, rx) = mpsc::channel();

    for arg in &args {
        let t = tx.clone();

        thread::spawn(move || {
            thread::sleep(Duration::from_millis(50));
            let _new_arg = arg.to_string() + "foo";
            t.send(arg);
        });
    }

    for _ in &args {
        println!("{}", rx.recv().unwrap());
    }
}

我从命令行读取所有参数并模拟对线程中的每个参数做一些工作。然后我打印出这项工作的结果,这是我使用通道完成的。

error[E0597]: `args` does not live long enough
  --> src/main.rs:11:17
   |
11 |     for arg in &args {
   |                 ^^^^ does not live long enough
...
24 | }
   | - borrowed value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

如果我理解得很好..args 的生命周期必须是static(即程序执行的整个时间),而它只存在于main 函数(?)的范围内。我不明白这背后的原因,以及如何解决它。

【问题讨论】:

    标签: rust


    【解决方案1】:

    问题在于产生一个后台线程。当您调用thread::spawn 时,您实际上必须将其中使用的任何资源的所有权传递给线程,因为它可能会无限期地运行,这意味着它的生命周期必须是'static

    有两种选择可以解决这个问题:最简单的一种是传递所有权。你的代码在这里

    let new_arg = arg.to_string() + "foo";
    t.send(arg);
    

    看起来您实际上想发送new_arg,在这种情况下,您可以在生成线程之前创建arg.to_string() 的拥有结果,从而无需传递引用arg

    另一个稍微复杂一点的想法,在某些时候可能有用,例如在crossbeam 中实现的作用域线程。这些绑定到一个显式范围,您可以在其中生成它们并在最后连接在一起。这看起来有点像这样:

    crossbeam::scope(|scope| {
        scope.spawn(|| {
            println!("Hello from a scoped thread!");
        });
    });
    

    查看the docs了解更多详情。

    【讨论】:

    • 由于向量是Strings 的集合并且在产生线程后未使用,我只需将arg 原样移动到线程中 - example。事实上,我什至可能会完全避开集合到 Vec - example
    • 谢谢@Shepmaster 和 aepsil0n,这次真的很适合我。 crossbeam::Scope.spawn() 也很好地解释了这个问题。
    猜你喜欢
    • 1970-01-01
    • 2015-07-31
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 2022-07-07
    • 1970-01-01
    • 2022-06-12
    • 1970-01-01
    相关资源
    最近更新 更多