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

时间:2015-03-02 17:58:48

标签: multithreading rust

我有一个结构:

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
    });
}

好借借检查员,我放弃了。如何将self的副本放到我的新主题上?

2 个答案:

答案 0 :(得分:4)

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

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

playpen

您可能还需要在功能中考虑按值self 按值,并让您的来电者决定是应该进行克隆,还是只是移动。

答案 1 :(得分:2)

作为替代解决方案,您可以使用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!");
}