我如何 return 一个包含来自线程的 Rc 的类型?
How can I return a type containing an Rc from a thread?
我正在生成一个线程,它构建本质上是一棵树的东西,稍后需要它,因此可以在线程外计算。举个例子,想想 Foo { inner: HashMap<Bar, Rc<FooBar>> }
。线程的关闭不会从周围环境捕获任何东西。
问题是 Rc
使整个类型 !Send
。这阻止了 Foo
被 returned 到生成线程。实际上,Rc
"poisons" Foo
.
我不明白为什么由派生线程创建并 returned 的类型仍然需要 Send
的原因:它强制所有内部类型(在这种情况下 Rc
在 HashMap
中,在 Foo
中变为 Send
。从派生线程的角度来看,这是无法修复的。
它强制生成的线程始终使用原子计数,而实际上两个线程同时访问引用计数器的可能性为零。
有没有办法 return(不是共享!)一个包含来自线程的 Rc
的类型?我是否遗漏了对 Send
的理解?
[T]here is actually zero possibility for both threads to access the refcounter simultaneously.
但是编译器无法理解,所以你不得不说"no really, trust me, I know it looks dodgy but it's actually safe."这就是unsafe
的目的。
应该像
一样简单
unsafe impl Send for Foo {}
来自Nomicon:
Rc
isn't Send or Sync (because the refcount is shared and unsynchronized).
使 Rc
本身成为 Send
是不安全的,因为 Rc
公开了一个接口,如果在线程之间发送该接口将是不安全的。但是 Foo
,正如您所描述的那样,公开了一个 在线程之间发送 不安全的接口,所以只需 unsafe impl
它就可以了。
假设,也就是说,接口可以安全地在线程之间发送。例如,Foo
不能有克隆方法和 returns 内部 Rc
(因为你可以使用它有效地 "smuggle" 一个裸 Rc
另一个线程来自 Foo
).
如果 Foo
并非 总是 可以安全发送,但您碰巧知道某些 特殊的 Foo
可以安全发送,更好的方法是暂时将其包装在 Send
类型中,如 所建议的那样。
Rust 语言对线程结束时不再有任何引用这一事实一无所知。事实上,它对线程 "starting" 或 "ending" 也一无所知。
从语言的角度来看,Rc
的克隆之一可能仍由线程拥有。一旦类型在线程上,就结束了。
当你有程序员知道但编译器不知道的东西时,unsafe
代码就是这种情况。
我不是 100% 确定,但是,据我所知,只要所有相互链接的 Rc
都在同一个线程上,它实际上是安全的。 应该是从线程返回值的情况。
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);
}
这个答案与 的不同之处在于,不安全代码的范围要小得多——它只涵盖通过线程返回的值。他们的回答将整个 MyTreeThing
类型标记为可以安全地跨线程发送,而不管上下文如何。这很好,只要你注意知道所有相关的 Rc
s 总是在线程之间批量移动。
另请参阅:
- How can I pass a reference to a stack variable to a thread?
我正在生成一个线程,它构建本质上是一棵树的东西,稍后需要它,因此可以在线程外计算。举个例子,想想 Foo { inner: HashMap<Bar, Rc<FooBar>> }
。线程的关闭不会从周围环境捕获任何东西。
问题是 Rc
使整个类型 !Send
。这阻止了 Foo
被 returned 到生成线程。实际上,Rc
"poisons" Foo
.
我不明白为什么由派生线程创建并 returned 的类型仍然需要 Send
的原因:它强制所有内部类型(在这种情况下 Rc
在 HashMap
中,在 Foo
中变为 Send
。从派生线程的角度来看,这是无法修复的。
它强制生成的线程始终使用原子计数,而实际上两个线程同时访问引用计数器的可能性为零。
有没有办法 return(不是共享!)一个包含来自线程的 Rc
的类型?我是否遗漏了对 Send
的理解?
[T]here is actually zero possibility for both threads to access the refcounter simultaneously.
但是编译器无法理解,所以你不得不说"no really, trust me, I know it looks dodgy but it's actually safe."这就是unsafe
的目的。
应该像
一样简单unsafe impl Send for Foo {}
来自Nomicon:
Rc
isn't Send or Sync (because the refcount is shared and unsynchronized).
使 Rc
本身成为 Send
是不安全的,因为 Rc
公开了一个接口,如果在线程之间发送该接口将是不安全的。但是 Foo
,正如您所描述的那样,公开了一个 在线程之间发送 不安全的接口,所以只需 unsafe impl
它就可以了。
假设,也就是说,接口可以安全地在线程之间发送。例如,Foo
不能有克隆方法和 returns 内部 Rc
(因为你可以使用它有效地 "smuggle" 一个裸 Rc
另一个线程来自 Foo
).
如果 Foo
并非 总是 可以安全发送,但您碰巧知道某些 特殊的 Foo
可以安全发送,更好的方法是暂时将其包装在 Send
类型中,如
Rust 语言对线程结束时不再有任何引用这一事实一无所知。事实上,它对线程 "starting" 或 "ending" 也一无所知。
从语言的角度来看,Rc
的克隆之一可能仍由线程拥有。一旦类型在线程上,就结束了。
当你有程序员知道但编译器不知道的东西时,unsafe
代码就是这种情况。
我不是 100% 确定,但是,据我所知,只要所有相互链接的 Rc
都在同一个线程上,它实际上是安全的。 应该是从线程返回值的情况。
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);
}
这个答案与 MyTreeThing
类型标记为可以安全地跨线程发送,而不管上下文如何。这很好,只要你注意知道所有相关的 Rc
s 总是在线程之间批量移动。
另请参阅:
- How can I pass a reference to a stack variable to a thread?