我搜索了Sync
但不是Send
的类型,因为它通常看起来像一个特征是另一个特征的超集(“实现Sync
的每种类型还实现了Send
“)。我找到了this question,但唯一真正的答案真的很复杂。
所以我想出了这段代码:
struct Foo(Rc<()>); // <-- private field
impl Foo {
fn my_clone(&mut self) -> Self { // <-- mutable borrow
Foo(self.0.clone())
}
}
我知道编译器不会为我的类型自动实现Send
或Sync
;但我对我可以手动安全实施的内容感兴趣。我想:
它应该能够实现Sync
:拥有不可变对Foo
的引用不会让我们做任何事情它(因为我们只能通过mutable / exclusive reference调用my_clone()
)。没有做任何事情,什么都不会出错,对吧?
它应该 能够实现Send
:我们可以在主线程中克隆我们的Foo
(在开始另一个之前)获取第二个对象。现在两个对象共享一些内存(引用计数,存储在Cell<usize>
中)。如果我现在可以将其中一个对象发送到另一个线程,则两个线程都拥有Foo
的所有权,引用相同的内存。因此,两个对象可以同时调用my_clone()
,从而导致对引用计数(数据竞争)的同时,不同步,可变的访问。
这种推理是正确的还是我错过了什么?
答案 0 :(得分:4)
我知道编译器不会为我的类型自动实现
Send
或Sync
。
实际上,编译器会自动为您实现Send
和Sync
,只有在它确定安全时才会这样做。
这个小程序:
use std::cell::Cell;
use std::sync::atomic::AtomicUsize;
fn ensure_sync<T: Sync>(_: T) {}
struct Automatic(AtomicUsize);
impl Automatic {
fn new() -> Automatic { Automatic(AtomicUsize::new(0)) }
}
fn main() {
ensure_sync(AtomicUsize::new(0));
ensure_sync(Automatic::new());
ensure_sync(Cell::new(0));
}
只有Cell::new(0)
行Automatic
上的错误为Sync
,因为其所有字段均为Sync
。
关于Foo
,Rc
既不是Sync
也不是Send
,所以编译器确实不会为您实现。
Foo
可以Sync
吗?
我相信 1 所以。只要没有其他操作添加到操作不可变引用的模块。现在或将来。
Foo
可以Send
吗?
我同意你的结论,但我认为你错过了另一种修改Cell
:drop
的方法。
事实上,您似乎通过使用Sync
而不是Send
的基础类型提出了Send
而非Sync
的类型。这可能是我的书呆子感觉,我觉得很有趣:)
1 在处理unsafe
代码时,我一无所知。很容易欺骗自己认为某些东西是安全的,只是因为一小部分细节没有引起人们的注意。