不需要克隆的情况下,是否可以使用线程共享数据?

9

当我将工作委派给线程时,通常会有一些数据比如下面的numbers会比所有线程都存活得更久:

use std::thread;

fn main() {
    let numbers = vec![1, 2, 3];

    let thread_a = thread::spawn(|| println!("{}", numbers.len()));
    let thread_b = thread::spawn(|| println!("{}", numbers.len()));

    thread_a.join().unwrap();
    thread_b.join().unwrap();
}

这段代码没有在任何地方进行修改,并且由于使用了join,可以保证线程已经使用完毕。然而,Rust的借用检查器无法判断:

error[E0373]: closure may outlive the current function, but it borrows `numbers`, which is owned by the current function
 --> src/main.rs:6:34
  |
6 |     let thread_a = thread::spawn(|| println!("{}", numbers.len()));
  |                                  ^^                ------- `numbers` is borrowed here
  |                                  |
  |                                  may outlive borrowed value `numbers`
  |
note: function requires argument type to outlive `'static`
 --> src/main.rs:6:20
  |
6 |     let thread_a = thread::spawn(|| println!("{}", numbers.len()));
  |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `numbers` (and any other referenced variables), use the `move` keyword
  |
6 |     let thread_a = thread::spawn(move || println!("{}", numbers.len()));
  |                                  ^^^^^^^

到目前为止,我看到的解决方案都涉及到克隆数据(或克隆数据的Arc)。不过,是否可能在没有任何克隆的情况下完成呢?

1个回答

7
你可能有误解:克隆Arc只是增加引用计数并复制指针;它不执行任何额外的分配。当然,创建Arc需要一次分配,但是,为了构造Vec,您已经在进行分配,因此一个额外的固定大小分配不太可能会造成影响。
如果你真正需要的只是长度,你可以在线程闭包之外计算它并将其存储在变量中;usize没有跨线程边界的问题。
问题在于编译器无法从join()的使用中推断出给定的线程绑定到有限的生命周期......它甚至不尝试。
在Rust 1.0之前,有一个thread::scoped构造函数,允许您传递非'static引用,但由于内存安全问题而必须被取消稳定性。请参见如何将对堆栈变量的引用传递给线程?以获取替代方案。

1
嗯,要将某些内容放入 Arc 中,您确实需要执行分配。 - Matthieu M.

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