Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何从线程返回包含Rc的类型?_Multithreading_Rust_Reference Counting - Fatal编程技术网

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)
——我们不需要知道树的方面。