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

Multithreading 复制结构以在另一个线程上使用,multithreading,rust,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 }); } 显然,编译器无法推断出适当的生存期,

我有一个结构:

struct MyData {
    x: i32
}
我想在此结构上异步启动一个长操作

我的第一次尝试是:

fn foo(&self) { //should return immediately
    std::thread::Thread::spawn(move || { 
        println!("{:?}",self.x); //consider a very long operation
    });
}
显然,编译器
无法推断出适当的生存期,因为需求冲突
,因为
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
    });
}
我认为这不会编译,因为现在的克隆与以前类似,位于堆栈框架上。我还尝试在线程内部执行
克隆
,我认为出于类似的原因,这也不会编译

然后我决定也许我可以使用
通道
将复制的数据推送到线程中,其理论是
通道
可以在线程之间神奇地移动(复制?)堆栈分配的数据,这是由。但是,编译器也无法推断此项的生存期:

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
    });
}
最后,我决定将我的结构显式复制到堆上,并向线程传递一个弧。但即使在这里,编译器也无法计算出一个生命周期:

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的副本?

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

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


您还可以考虑在函数中按值使用<代码>自身>代码>,并让调用方决定它是否应该创建一个克隆,或者只是一个移动。

< P>作为一个替代的解决方案,您可以使用和维护线程的句柄。这允许线程保存引用,而无需将其复制到:

#![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!");
}
#![功能(旧io、标准misc)]
使用std::thread::{self,JoinGuard};
使用std::old_io::timer;
使用std::time::duration::duration;
结构MyData{
x:i32,
}
//立即返回
impl MyData{
fn foo(&self)->JoinGuard{
线程::作用域(移动| |{
计时器::睡眠(持续时间::毫秒(300));
println!(“{:?}”,self.x);//考虑一个很长的操作
计时器::睡眠(持续时间::毫秒(300));
})
}
}
fn main(){
设d=MyData{x:42};
设_thread=d.foo();
println!(“我太快了!”);
}

哦,我觉得这很有道理。谢谢你的澄清!这适用于所提出的问题,但在某些情况下,仅仅实现克隆似乎不够好--@Drew编译器告诉您,使用泛型参数时遇到的问题是,引用的生存期太短,您应该根据thread::spawn函数的要求添加“静态生存期界限”。最近,为了允许作用域线程(见下面@Shepmaster的示例),发送的更改不再意味着“静态”了,我对为什么一开始会这样感到困惑。原来,
JoinGuard
有一个生存期参数,而生存期省略使其与
&self
参数的未命名生存期相同。这很好,但有一个警告:借用将持续到
JoinGuard
被删除。我们必须意识到这一点,它也使调用代码比另一个答案更加复杂。不幸的是,方法签名是由一个特征指定的。我当然可以修改它以添加一个JoinGuard作为返回参数,但是这个函数的其他实现不需要一个。。。