问题描述
我无法在线程之间共享引用.
I am unable to share a reference between threads.
trait Facade { /*some functions*/ }
struct Client<'a> {
facade: &'a mut Facade,
join_grd: thread::JoinGuard<'a()>,
}
impl<'a> Client<'a> {
pub fn new(my_facade: &'a mut Facade) -> Client<'a> {
Client {
facade: my_facade,
join_grd: thread::scoped(|| Client::start(my_facade)),
}
}
fn start(my_facade: &'a mut Facade) { unimplemented!() }
}
考虑到我在Rust中的新手身份,我对概念和错误感到困惑.如何实现以上目标?
Given my newbie status in Rust, I'm getting confused with concepts and errors. How do I achieve the above ?
推荐答案
由于Rust中存在可变的别名保证,因此我很确定您无法执行此操作.在Rust中,您不能同时有两个对同一事物的可变引用,但这正是代码中发生的事情:将my_facade
存储到Client
的字段中,并且同时尝试将其传递给另一个线程中的start()
方法.这将需要具有对同一Facade
的两个可变引用,这是不允许的.
I'm pretty sure you can't do this due to the mutable aliasing guarantees in Rust. In Rust you can't have two mutable references to the same thing at the same time, but this is exactly what happens in your code: you store my_facade
to the field of Client
and at the same time you are trying to pass it to start()
method in another thread. This would require having two mutable references to the same Facade
which is disallowed.
编译器在您的代码上发出的实际错误是由您使用固定的闭包引起的.如果将thread::scoped()
实例化更改为此:
The actual errors which compiler emits on your code are caused by that you're using a non-moving closure. If you change thread::scoped()
instantiation to this:
join_grd: thread::scoped(move || Client::start(my_facade))
错误会更明智:
test.rs:16:60: 16:69 error: cannot move `my_facade` into closure because it is borrowed
test.rs:16 join_grd: thread::scoped(move || Client::start(my_facade))
^~~~~~~~~
test.rs:15:21: 15:30 note: borrow of `*my_facade` occurs here
test.rs:15 facade: my_facade,
^~~~~~~~~
这实质上意味着,由于&mut
引用是唯一的并且被移动而不是复制,因此您无法复制它们.使用常规&
引用而不是&mut
(以及Facade
上的附加Sync
父代特征)的类似代码也可以正常工作.
This essentially means that since &mut
references are unique and are moved instead of copied, you can't duplicate them. Similar code with the regular &
reference instead of &mut
(and an additional Sync
parent trait on Facade
) works fine.
您必须重新考虑您的体系结构才能解决此错误.仅凭这段代码很难理解您想要什么,因此我无法给出确切的建议,但是您可以考虑使用和 Mutex
如果要在线程之间共享可变状态.
You have to rethink your architecture to fix this error. It is difficult to understand what you want from this piece of code alone, so I can't give any exact advices, but you may consider using Arc
and Mutex
if you want to share mutable state between threads.
Arc/Mutex
的原始用法是这样的:
Naive usage of Arc/Mutex
like this:
fn start(my_facade: Arc<Mutex<Facade>>)
无效,因为Facade
是一个特征,而不是常规类型.当使用特征作为类型时,实际上是在选择动态分发以特征对象的形式.简而言之,特质对象不能直接使用.它们应该始终在指针后面.您的原始程序还使用了特征对象(&'a mut Facade
是特征对象).理想情况下,我们应该能够使用任何类型的智能指针来形成特征对象,并且理想情况下Arc<Mutex<Facade>>
应该可以工作,但是不幸的是,目前只能使用&
,&mut
或Box
创建特征对象:
won't work because Facade
is a trait, not a regular type. When you use traits as types, you're in fact opting into dynamic dispatch in form of trait objects. In short, trait objects can't be used directly; they should always be behind a pointer. Your original program also used trait objects (&'a mut Facade
is a trait object). Ideally we should be able to form trait objects with any kind of smart pointer, and ideally Arc<Mutex<Facade>>
should work, but unfortunately for now trait objects can only be created with &
, &mut
or Box
:
fn start(my_facade: Arc<Mutex<Box<Facade>>>)
这是您观察到的关于Sized
的错误的原因.
This is the reason of the error about Sized
that you observe.
但是,您还应该考虑根本不使用特征对象,而只使用泛型:
However, you should also consider not using trait objects at all and just use generics:
trait Facade: Send { fn f(&self); }
struct Client<'a, F: Facade> { // '
facade: Arc<Mutex<F>>,
join_grd: thread::JoinGuard<'a, ()>, // '
}
impl<'a, F: Facade+'a> Client<'a, F> { // '
pub fn new(my_facade: Arc<Mutex<F>>) -> Client<'a, F> { // '
let my_facade_2 = my_facade.clone(); // clone the Arc pointer
Client {
facade: my_facade,
join_grd: thread::scoped(move || Client::start(my_facade_2)),
}
}
fn start(my_facade: Arc<Mutex<F>>) { unimplemented!() }
}
您还需要在特征本身(如上例)或F
类型变量(如在F: Facade+Send+'a
中)上添加Send
绑定,因为只有Send
数据可以在线程之间安全地传输,因此您需要直接指定F
为Send
或作为Facade
的超特征约束.
You also need to add Send
bound either on the trait itself (as in the example above) or on F
type variable (as in F: Facade+Send+'a
) because only Send
data may be transferred between threads safely, so you need to specify that F
is Send
, either directly or as a supertrait constraint on Facade
.
这篇关于如何跨线程共享引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!