[英]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()
函数。
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.