这种略微修改的Rc<(>)是同步,但不是发送,对吗?

时间:2017-01-25 07:55:05

标签: multithreading rust

我搜索了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())
    }
}

我知道编译器不会为我的类型自动实现SendSync;但我对我可以手动安全实施的内容感兴趣。我想:

  • 它应该能够实现Sync :拥有不可变Foo的引用不会让我们做任何事情它(因为我们只能通过mutable / exclusive reference调用my_clone())。没有做任何事情,什么都不会出错,对吧?

  • 它应该 能够实现Send :我们可以在主线程中克隆我们的Foo(在开始另一个之前)获取第二个对象。现在两个对象共享一些内存(引用计数,存储在Cell<usize>中)。如果我现在可以将其中一个对象发送到另一个线程,则两个线程都拥有Foo的所有权,引用相同的内存。因此,两个对象可以同时调用my_clone(),从而导致对引用计数(数据竞争)的同时,不同步,可变的访问。

这种推理是正确的还是我错过了什么?

1 个答案:

答案 0 :(得分:4)

  

我知道编译器不会为我的类型自动实现SendSync

实际上,编译器会自动为您实现SendSync,只有在它确定安全时才会这样做。

这个小程序:

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

关于FooRc既不是Sync也不是Send,所以编译器确实不会为您实现。

Foo可以Sync吗?

相信 1 所以。只要没有其他操作添加到操作不可变引用的模块。现在或将来。

Foo可以Send吗?

我同意你的结论,但我认为你错过了另一种修改Celldrop的方法。

事实上,您似乎通过使用Sync而不是Send的基础类型提出了Send而非Sync的类型。这可能是我的书呆子感觉,我觉得很有趣:)

1 在处理unsafe代码时,我一无所知。很容易欺骗自己认为某些东西是安全的,只是因为一小部分细节没有引起人们的注意。