作用域线程 (Scoped threads)

我们到目前为止讨论的所有生命周期问题都有一个共同根源: 被 spawn 的线程可能比父线程更长寿。
我们可以通过使用作用域线程 (scoped threads) 绕开这个问题。

let v = vec![1, 2, 3];
let midpoint = v.len() / 2;

std::thread::scope(|scope| {
    scope.spawn(|| {
        let first = &v[..midpoint];
        println!("Here's the first half of v: {first:?}");
    });
    scope.spawn(|| {
        let second = &v[midpoint..];
        println!("Here's the second half of v: {second:?}");
    });
});

println!("Here's v: {v:?}");

我们逐步拆解发生了什么。

scope

std::thread::scope 函数创建一个新的作用域 (scope)
std::thread::scope 接受一个闭包作为输入,闭包带一个参数:Scope 实例。

作用域内的 spawn (Scoped spawns)

Scope 暴露了一个 spawn 方法。
std::thread::spawn 不同,所有通过 Scope spawn 的线程在作用域结束时都会自动 join

如果我们把前面的例子"翻译"成 std::thread::spawn,会是这样:

let v = vec![1, 2, 3];
let midpoint = v.len() / 2;

let handle1 = std::thread::spawn(|| {
    let first = &v[..midpoint];
    println!("Here's the first half of v: {first:?}");
});
let handle2 = std::thread::spawn(|| {
    let second = &v[midpoint..];
    println!("Here's the second half of v: {second:?}");
});

handle1.join().unwrap();
handle2.join().unwrap();

println!("Here's v: {v:?}");

从环境借用 (Borrowing from the environment)

不过翻译过来的版本不会通过编译:编译器会抱怨 &v 不能从被 spawn 的线程里使用,因为它的生命周期不是 'static

std::thread::scope 没有这个问题——你可以安全地从环境借用 (safely borrow from the environment)

我们的例子里,v 在 spawn 之前就创建了。 它要在 scope 返回 之后 才被丢弃。同时,所有在 scope 内 spawn 的线程都保证在 scope 返回 之前 完成,因此不存在悬垂引用的风险。

编译器不会抱怨!

原文链接:英文原文