复制结构以在另一个线程上使用

Copying a struct for use on another thread

我有一个结构:

struct MyData {
    x: i32
}

我想在此结构上异步启动一个长操作。

我的第一次尝试是这样的:

fn foo(&self) { //should return immediately
    std::thread::Thread::spawn(move || { 
        println!("{:?}",self.x); //consider a very long operation
    });
}

显然编译器 cannot infer an appropriate lifetime due to conflicting requirements 因为 self 可能在堆栈帧上,因此不能保证在操作 运行 时存在于不同的堆栈帧上。

为了解决这个问题,我尝试复制 self 并将该副本提供给新线程:

fn foo(&self) { //should return immediately
    let clone = self.clone();
    std::thread::Thread::spawn(move || { 
        println!("{:?}",clone.x); //consider a very long operation
    });
}

我认为无法编译,因为现在 clone 位于与之前类似的堆栈帧上。我还尝试在线程内执行 clone,但我认为出于类似原因,这也无法编译。

然后我决定也许我可以使用 channel 将复制的数据推送到线程中,理论上也许 channel 可以神奇地移动(复制?)线程之间的堆栈分配数据,这是 this example in the documentation 建议的。但是,编译器也不能为此推断生命周期:

fn foo(&self) { //should return immediately
    let (tx, rx) = std::sync::mpsc::channel();
    tx.send(self.clone());
    std::thread::Thread::spawn(move || { 
        println!("{:?}",rx.recv().unwrap().x); //consider a very long operation
    });
}

最后,我决定只将我的结构显式复制到堆上,并将 Arc 传递到线程中。但即使在这里,编译器也无法计算出生命周期:

fn foo(&self) { //should return immediately
    let arc = std::sync::Arc::new(self.clone());
    std::thread::Thread::spawn(move || { 
        println!("{:?}",arc.clone().x); //consider a very long operation
    });
}

好吧借checker,我放弃了。如何将 self 的副本添加到我的新线程?

我认为你的问题仅仅是因为你的结构没有派生出 Clone 特性。您可以通过在结构定义之前添加 #[derive(Clone)] 来编译和 运行 第二个示例。

我在这里的编译器行为中不明白的是它试图在这里使用的 .clone() 函数。您的结构确实没有实现 Clone 特性,因此默认情况下不应具有 .clone() 函数。

playpen

您可能还需要考虑在您的函数中采用 self by value,并让您的调用者决定是否应该进行克隆,或者只是移动。

作为替代解决方案,您可以使用 thread::scoped 并维护线程的句柄。这允许线程持有一个引用,而不需要将其复制到:

#![feature(old_io,std_misc)]

use std::thread::{self,JoinGuard};
use std::old_io::timer;
use std::time::duration::Duration;

struct MyData {
    x: i32,
}

// returns immediately
impl MyData {
    fn foo(&self) -> JoinGuard<()> { 
        thread::scoped(move || { 
            timer::sleep(Duration::milliseconds(300));
            println!("{:?}", self.x); //consider a very long operation
            timer::sleep(Duration::milliseconds(300));
        })
    }
}

fn main() {
    let d = MyData { x: 42 };
    let _thread = d.foo();
    println!("I'm so fast!");
}