Send如果一种类型可以安全地从一个线程移动到另一个线程(根据 Rust 书籍),则该类型可以是。我理解非原子递增/递减的作用Rc,但我不明白这会如何使其在以下示例中变得不安全:
use std::rc::Rc;
use std::{thread};
fn main() {
// x1 initialized - count = 1
let x1 = Rc::new(5);
// x1 cloned - count = 2. No other threads exist to cause issues due to non-atomic increment
let x2 = Rc::clone(&x1);
// x2 moved from thead-main to thread-other. This move occurs before the thread actually runs
// x2 in main cannot be used after this point and drop wont be called on it.
// This is a move so no increment/decrement takes place.
// main can't move forward unless the move is complete so drop/decrement wont happen
thread::spawn(move || {
// Technically "moving" x2 from thread-main to thread-other did not cause problems
// so why is `Rc` not `Send`?
println!("{:?}", x2);
});
}
Run Code Online (Sandbox Code Playgroud)
据我了解,Send仅讨论可能的移动,因为没有移动会导致减量/增量,为什么 Rc 不发送?
您问为什么编译器不证明您的代码是安全的。这是不可能的。编译器不可能证明图灵完备程序的任何重要语义属性(赖斯定理)。是的,你也许可以在你的小例子中证明这一点,但除此之外,这将是非常困难的。
所以编译器必须简化并悲观。
Send是一个特征,在类型系统级别运行,不了解运行时环境。并且Rc,不得不假设最坏的情况,并没有实施它。是的,如果您将所有参考文献一起传递,那就安全了。但没有办法证明你在一般情况下都这样做了。
如果您只有一份参考资料,则可以使用Rc::unwrap. 否则,您可以使用unsafe,这是处理编译器无法证明安全的事情的逃生舱口。但随后就需要您来确保代码的安全。
另请注意,此代码是不安全的。当变量超出范围时,变量将被删除 - for x1,这将是在线程生成之后,这意味着两个线程将同时访问它。但有一个简单的解决办法——x1提前删除。
| 归档时间: |
|
| 查看次数: |
258 次 |
| 最近记录: |