这个稍加修改的 Rc<()> 是 Sync,但不是 Send,对吧?
Posted
技术标签:
【中文标题】这个稍加修改的 Rc<()> 是 Sync,但不是 Send,对吧?【英文标题】:This slightly modified Rc<()> is Sync, but not Send, right? 【发布时间】:2017-01-25 07:55:05 【问题描述】:我搜索了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
的不可变引用不会让我们对它做任何事情(因为我们只能通过可变/独占引用调用my_clone()
)。而且不做任何事情,什么都不会出错,对吧?
应该不能够实现Send
:我们可以在主线程中(在启动另一个线程之前)克隆我们的Foo
以获得第二个对象。现在两个对象共享一些内存(引用计数,存储在Cell<usize>
中)。如果我现在可以将其中一个对象发送到另一个线程,那么两个线程都将拥有Foo
的所有权,引用相同的内存。因此,两个对象可以同时调用my_clone()
,从而导致对引用计数的同时、非同步、可变访问(数据竞争)。
这个推理是正确的还是我遗漏了什么?
【问题讨论】:
【参考方案1】:我知道编译器不会为我的类型自动实现
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
。
因此,确实,您似乎通过使用Send
而不是Sync
的基础类型来提出Sync
而不是Send
的类型。这可能是我的书呆子感觉,我觉得这很有趣:)
1在处理unsafe
代码时,我什么都不确定。很容易自欺欺人地认为某事是安全的,仅仅因为一个微小的细节没有引起注意。
【讨论】:
以上是关于这个稍加修改的 Rc<()> 是 Sync,但不是 Send,对吧?的主要内容,如果未能解决你的问题,请参考以下文章