将两个对象(其中一个对象持有对另一个对象的引用)传递到线程中
Passing two objects, where one holds a reference to another, into a thread
我有两个对象,其中第二个对象需要第一个对象比它长寿,因为它持有对第一个对象的引用。我需要将它们都移到一个线程中,但编译器抱怨第一个线程不够长。这是代码:
use std::thread;
trait Facade: Sync {
fn add(&self) -> u32;
}
struct RoutingNode<'a> {
facade: &'a (Facade + 'a),
}
impl<'a> RoutingNode<'a> {
fn new(facade: &'a Facade) -> RoutingNode<'a> {
RoutingNode { facade: facade }
}
}
fn main() {
struct MyFacade;
impl Facade for MyFacade {
fn add(&self) -> u32 {
999u32
}
}
let facade = MyFacade;
let routing = RoutingNode::new(&facade);
let t = thread::spawn(move || {
let f = facade;
let r = routing;
});
t.join();
}
错误:
error: `facade` does not live long enough
--> <anon>:27:37
|
27 | let routing = RoutingNode::new(&facade);
| ^^^^^^ does not live long enough
...
35 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
我相信我明白错误告诉我的是什么:一旦 facade
对象移动到线程,引用将不再有效。但是我无法找到解决这个问题的有效方法,假设我想保持结构完好无损。
。让我们看一个简化的内存示例:
let a = Struct1; // the memory for Struct1 is on the stack at 0x1000
let b = &a; // the value of b is 0x1000
let c = a; // This moves a to c, and it now sits on the stack at 0x2000
哦不,如果我们尝试使用 b
中的引用(它仍然指向 0x1000
),那么我们将访问未定义的内存!这正是 Rust 帮助防止的 class 个错误 - Rust 万岁!
如何修复取决于您的实际情况。在你的例子中,我建议 moving the facade
into the thread,then create the RoutingNode
on the reference在线程的堆栈中:
let facade = MyFacade;
let t = thread::spawn(move || {
let f = facade;
let r = RoutingNode::new(&f);
});
这是人们通常说的答案部分"but that demo code isn't what my real code does",所以我期待额外的复杂性!
unfortunately I can't use this solution as I need to use the routing object in the main thread prior to sending it to the other thread
我在这里看到了一些选项。最直接的方法是让包装对象 取得包装对象的所有权 ,而不仅仅是引用:
use std::thread;
trait Facade: Sync {
fn add(&self) -> u32;
}
struct RoutingNode<F> {
facade: F,
}
impl<F> RoutingNode<F>
where
F: Facade,
{
fn new(facade: F) -> RoutingNode<F> {
RoutingNode { facade }
}
}
fn main() {
struct MyFacade;
impl Facade for MyFacade {
fn add(&self) -> u32 {
999u32
}
}
let facade = MyFacade;
let routing = RoutingNode::new(facade);
let t = thread::spawn(move || {
let r = routing;
});
t.join().expect("Unable to join");
}
Another option is to use scoped threads。这允许您拥有一个可以从闭包外部引用的线程,但是 必须在借用的变量超出范围之前加入 。范围线程的两个潜在提供者:
使用横梁:
extern crate crossbeam;
let facade = MyFacade;
let routing = RoutingNode::new(&facade);
crossbeam::scope(|scope| {
scope.spawn(|| {
let r = routing;
})
});
如果第一个选项对您的情况具有语义意义,我更喜欢第一个选项。我也喜欢第二个选项,因为线程的生命周期通常不需要是整个程序。
我有两个对象,其中第二个对象需要第一个对象比它长寿,因为它持有对第一个对象的引用。我需要将它们都移到一个线程中,但编译器抱怨第一个线程不够长。这是代码:
use std::thread;
trait Facade: Sync {
fn add(&self) -> u32;
}
struct RoutingNode<'a> {
facade: &'a (Facade + 'a),
}
impl<'a> RoutingNode<'a> {
fn new(facade: &'a Facade) -> RoutingNode<'a> {
RoutingNode { facade: facade }
}
}
fn main() {
struct MyFacade;
impl Facade for MyFacade {
fn add(&self) -> u32 {
999u32
}
}
let facade = MyFacade;
let routing = RoutingNode::new(&facade);
let t = thread::spawn(move || {
let f = facade;
let r = routing;
});
t.join();
}
错误:
error: `facade` does not live long enough
--> <anon>:27:37
|
27 | let routing = RoutingNode::new(&facade);
| ^^^^^^ does not live long enough
...
35 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
我相信我明白错误告诉我的是什么:一旦 facade
对象移动到线程,引用将不再有效。但是我无法找到解决这个问题的有效方法,假设我想保持结构完好无损。
let a = Struct1; // the memory for Struct1 is on the stack at 0x1000
let b = &a; // the value of b is 0x1000
let c = a; // This moves a to c, and it now sits on the stack at 0x2000
哦不,如果我们尝试使用 b
中的引用(它仍然指向 0x1000
),那么我们将访问未定义的内存!这正是 Rust 帮助防止的 class 个错误 - Rust 万岁!
如何修复取决于您的实际情况。在你的例子中,我建议 moving the facade
into the thread,then create the RoutingNode
on the reference在线程的堆栈中:
let facade = MyFacade;
let t = thread::spawn(move || {
let f = facade;
let r = RoutingNode::new(&f);
});
这是人们通常说的答案部分"but that demo code isn't what my real code does",所以我期待额外的复杂性!
unfortunately I can't use this solution as I need to use the routing object in the main thread prior to sending it to the other thread
我在这里看到了一些选项。最直接的方法是让包装对象 取得包装对象的所有权 ,而不仅仅是引用:
use std::thread;
trait Facade: Sync {
fn add(&self) -> u32;
}
struct RoutingNode<F> {
facade: F,
}
impl<F> RoutingNode<F>
where
F: Facade,
{
fn new(facade: F) -> RoutingNode<F> {
RoutingNode { facade }
}
}
fn main() {
struct MyFacade;
impl Facade for MyFacade {
fn add(&self) -> u32 {
999u32
}
}
let facade = MyFacade;
let routing = RoutingNode::new(facade);
let t = thread::spawn(move || {
let r = routing;
});
t.join().expect("Unable to join");
}
Another option is to use scoped threads。这允许您拥有一个可以从闭包外部引用的线程,但是 必须在借用的变量超出范围之前加入 。范围线程的两个潜在提供者:
使用横梁:
extern crate crossbeam;
let facade = MyFacade;
let routing = RoutingNode::new(&facade);
crossbeam::scope(|scope| {
scope.spawn(|| {
let r = routing;
})
});
如果第一个选项对您的情况具有语义意义,我更喜欢第一个选项。我也喜欢第二个选项,因为线程的生命周期通常不需要是整个程序。