Multithreading 如何从线程返回包含Rc的类型?
我正在生成一个线程,它构建了本质上是一棵树的东西,这是稍后需要的,因此可以在非线程中进行计算。为了举例,考虑一个Multithreading 如何从线程返回包含Rc的类型?,multithreading,rust,reference-counting,Multithreading,Rust,Reference Counting,我正在生成一个线程,它构建了本质上是一棵树的东西,这是稍后需要的,因此可以在非线程中进行计算。为了举例,考虑一个Foo{inner:HashMap}。线程的闭包不会捕获周围环境中的任何内容 问题是,Rc生成整个类型的!发送。这将阻止Foo返回到生成线程。实际上,Rc“毒药”Foo 我看不出由派生线程创建并返回的类型仍然需要是Send的原因:它强制所有内部类型(在本例中,HashMap中的Rc,Foo中的Send)为Send。从派生线程的角度来看,这是不可执行的。 它强制生成的线程始终使用原子计数
Foo{inner:HashMap}
。线程的闭包不会捕获周围环境中的任何内容
问题是,Rc
生成整个类型的!发送
。这将阻止Foo
返回到生成线程。实际上,Rc
“毒药”Foo
我看不出由派生线程创建并返回的类型仍然需要是Send
的原因:它强制所有内部类型(在本例中,HashMap
中的Rc
,Foo
中的Send
)为Send。从派生线程的角度来看,这是不可执行的。
它强制生成的线程始终使用原子计数,而实际上两个线程同时访问refcounter的可能性为零
有没有一种方法可以从线程返回(而不是共享!)包含Rc
的类型?我对Send
的理解是否遗漏了什么
[T] 实际上,两个线程同时访问refcounter的可能性为零
但是编译器不能理解这一点,所以你必须说“不,真的,相信我,我知道它看起来很狡猾,但实际上是安全的。”这就是不安全的原因
它应该尽可能简单
unsafe impl Send for Foo {}
从:
Rc
不发送或同步(因为refcount是共享和不同步的)
让Rc
本身Send
是不安全的,因为Rc
暴露了一个在线程之间发送时会不安全的接口。但是Foo
正如您所描述的,暴露了一个在线程之间发送时不会不安全的接口,所以只需unsafe impl
就可以了
假设接口可以安全地在线程之间发送。Foo
不能有一个克隆并返回内部Rc
的方法,例如(因为您可以使用该方法通过Foo
有效地“走私”一个裸Rc
到另一个线程中)
如果Foo
发送并不总是安全的,但是您碰巧知道某些特定的Foo
发送是安全的,那么更好的方法是将其临时包装为send
类型,正如所建议的那样。Rust语言不知道当线程结束时,它不再具有任何引用这一事实实际上,它也不知道线程的“开始”或“结束”
从语言的角度来看,Rc
的一个克隆可能仍然属于线程。一旦类型位于线程上,就结束了
当你有程序员知道但编译器不知道的东西时,这就是不安全的情况
我不是100%确定,但就我所知,只要所有互连的Rc
s都在同一个线程上,它实际上是安全的。从线程返回值应该是这样的
use std::{rc::Rc, thread};
type MyTreeThing = Rc<i32>;
struct ReturningAnRcAcrossThreadsIsSafe(MyTreeThing);
// I copied this from Stack Overflow without reading the text and
// stating why I think this code is actually safe.
unsafe impl Send for ReturningAnRcAcrossThreadsIsSafe {}
fn main() {
let t = thread::spawn(|| ReturningAnRcAcrossThreadsIsSafe(Rc::new(42)));
let a = t.join().unwrap().0;
println!("{}", a);
}
使用std:{rc::rc,thread};
类型MyTreeThing=Rc;
结构返回NRCAcrossThreadSisSafe(MyTreeThing);
//我从Stack Overflow复制了这个,没有阅读文本和
//说明为什么我认为这个代码实际上是安全的。
不安全的impl发送以返回nrcassthreadsissafe{}
fn main(){
让t=thread::spawn(| | returninganrcassthreadsissafe(Rc::new(42));
设a=t.join().unwrap().0;
println!(“{}”,a);
}
这个答案与不安全代码的不同之处在于,不安全代码的作用域要小得多——它只覆盖线程中返回的值。他们的答案将整个MyTreeThing
类型标记为可以跨线程安全发送,而不管上下文如何。只要您注意知道所有相关的Rc
s都是安全的,就可以了总是在线程之间大量移动
另见:
实际的类型更复杂,实际上不相关。关键是在类型堆栈的深处有一个Rc
(或任何其他!Send
)我无法控制。我试图避免对“首先,如果值是Foo
,那么这不是一棵树,而是一个广义的二次双焦点Van de gren图!”……你可以说你有一个Foo(Rc)
——我们不需要知道树的方面。