如何跨线程共享引用? [英] How can I share references across threads?

查看:77
本文介绍了如何跨线程共享引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法在线程之间共享引用.

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是一个特征,而不是常规类型.当使用特征作为类型时,实际上是在选择

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数据可以在线程之间安全地传输,因此您需要直接指定FSend或作为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.

这篇关于如何跨线程共享引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆