简体   繁体   English

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

[英]Copying a struct for use on another thread

I have a struct: 我有一个结构:

struct MyData {
    x: i32
}

I want to asynchronously start a long operation on this struct. 我想在此结构上异步启动长操作。

My first attempt was this: 我的第一次尝试是:

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

Clearly the compiler cannot infer an appropriate lifetime due to conflicting requirements because self may be on the stack frame and thus cannot be guaranteed to exist by the time the operation is running on a different stack frame. 显然, cannot infer an appropriate lifetime due to conflicting requirements ,编译器cannot infer an appropriate lifetime due to conflicting requirements因为self可能位于堆栈框架上,因此无法保证操作在不同的堆栈框架上运行时就已经存在。

To solve this, I attempted to make a copy of self and provide that copy to the new thread: 为了解决这个问题,我尝试制作一个self的副本并将该副本提供给新线程:

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

I think that does not compile because now clone is on the stack frame which is similar to before. 我认为这不能编译,因为现在clone位于堆栈框架上,与以前类似。 I also tried to do the clone inside the thread, and that does not compile either, I think for similar reasons. 我也尝试在线程内进行clone ,但出于同样的原因,它也无法编译。

Then I decided maybe I could use a channel to push the copied data into the thread, on the theory that perhaps channel can magically move (copy?) stack-allocated data between threads, which is suggested by this example in the documentation . 然后我决定也许可以使用channel将复制的数据推入线程中,这是基于以下理论: channel可以神奇地在线程之间移动(复制?)堆栈分配的数据, 此示例在文档中提出 However the compiler cannot infer a lifetime for this either: 但是,编译器无法为此推断寿命:

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

Finally, I decided to just copy my struct onto the heap explicitly, and pass an Arc into the thread. 最后,我决定只是将我的结构显式复制到堆上,然后将Arc传递到线程中。 But not even here can the compiler figure out a lifetime: 但即使在这里,编译器也无法确定生命周期:

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

Okay borrow checker, I give up. 好吧,借支票员,我放弃。 How do I get a copy of self onto my new thread? 我如何获得的一份self到我新的线程?

I think your issue is simply because your structure does not derive the Clone trait. 我认为您的问题仅仅是因为您的结构没有派生Clone特征。 You can get your second example to compile and run by adding a #[derive(Clone)] before your struct's definition. 您可以通过在结构的定义之前添加#[derive(Clone)]来获取第二个示例进行编译和运行。

What I don't understand in the compiler behaviour here is what .clone() function it tried to use here. 我在此处的编译器行为中不了解的是它尝试在此处使用的.clone()函数。 Your structure indeed did not implement the Clone trait so should not by default have a .clone() function. 您的结构确实没有实现Clone特性,因此默认情况下不应具有.clone()函数。

playpen 围栏

You may also want to consider in your function taking self by value , and let your caller decide whether it should make a clone, or just a move. 您也可以在你的函数取来考虑self 的价值 ,并让您的来电者决定是否应该克隆,或只是一招。

As an alternative solution, you could use thread::scoped and maintain a handle to the thread. 作为替代解决方案,您可以使用thread::scoped并维护该线程的句柄。 This allows the thread to hold a reference, without the need to copy it in: 这使线程可以保留引用,而无需将其复制到:

#![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!");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM