线程引用需要静态生命周期吗?

4

虽然直觉上传递给派生线程的引用需要具有静态生命周期,但我不清楚以下代码究竟是什么原因导致无法编译:

use std::sync::Arc;
use std::sync::Mutex;

struct M;

fn do_something(m : Arc<Mutex<&M>>) {
    println!("Ha, do nothing!");
}

fn main() {
    let a = M;
    {
        let c : Arc<Mutex<&M>> = Arc::new(Mutex::new(&a));
        for i in 0..2 {
            let c_clone = c.clone();
            ::std::thread::spawn(move || do_something(c_clone));
        }
    }
}

编译这个小程序会出现以下错误:
$ rustc -o test test.rs
test.rs:13:55: 13:56 error: `a` does not live long enough
test.rs:13         let c : Arc<Mutex<&M>> = Arc::new(Mutex::new(&a));
                                                             ^
note: reference must be valid for the static lifetime...

在我看来变量a将比c_clone存在更久,这是此情况下的关键所在...?希望有人能帮我理解我漏掉了什么!


线程可以从其他线程启动。无法静态知道哪个线程正在生成线程,因此保守(读作安全)的解决方案是要求所有引用必须具有“static生命周期”。在main中创建的项没有该生命周期,因为它们在main退出之前被销毁。 - Shepmaster
1个回答

6

本质上,ArcMutex的封装是多余的:你正在传递对本地堆栈上某个东西的引用。当你使用std::thread::spawn生成一个线程时,没有任何东西将生命周期链接在一起;主线程完全可以结束并释放其中的任何东西——在这种情况下,包括a——在它生成任何其他线程之前,即使是开始执行;因此,在这种情况下,a可能会在生成的线程执行任何操作之前引用已释放的内存,从而使c_clone成为悬挂指针。这就是为什么生成的线程的闭包环境必须是'static的原因。


这里是 std::thread::spawn 的文档参考链接:https://doc.rust-lang.org/std/thread/fn.spawn.html - Mokosha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接