我搜索的类型是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的引用是不可变的,因此我们无法对其进行任何处理(因为我们只能通过可变/专有引用来调用my_clone())。如果不做任何事情,什么都不会出错,对吗?
  • 它应该无法实现Send :我们可以在主线程中克隆Foo(在启动另一个线程之前)以获取第二个对象。现在,两个对象共享一些内存(引用计数,存储在Cell<usize>中)。如果现在我可以将这些对象之一发送到另一个线程,则两个线程都将拥有Foo的所有权,并引用相同的内存。因此,两个对象可以同时调用my_clone(),从而导致对引用计数的同时,不同步,可变访问(数据竞争)。

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

    最佳答案



    实际上,只有在编译器确定可以安全地执行此操作时,编译器才会自动为您实现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行上出错,SyncFoo

    关于RcSync既不是Send也不是Foo,因此编译器实际上也不会为您实现任何一种。
    Sync可以是Foo吗?

    我相信1。只要不对基于不变引用的模块添加任何其他操作即可。现在或将来。
    Send可以是Cell吗?

    我同意您的结论,但是我认为您错过了另一种修改drop的方法:Sync

    因此,实际上,您似乎通过使用Send而非Send的基础类型想出了Sync而不是unsafe的类型。这可能是我的 Nerd 感觉,我觉得这很有趣:)

    1在处理ojit_code代码时,我永远不会确定任何事情。愚弄自己以为是安全的,这很容易,仅仅是因为一个很小的细节就引起了人们的注意。

    关于multithreading - 这个经过稍微修改的Rc <()>是Sync,但不是Send,对吧?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41846177/

    10-12 20:09