This slightly modified Rc <()> is Sync, but not Send, right?

I searched for Sync types, but not Send , because it often looks like one attribute - it is a superset of the other ("each type that implements Sync also implements Send "). I found this question , but the only real answer is really complicated.

So, I came up with this code:

 struct Foo(Rc<()>); // <-- private field impl Foo { fn my_clone(&mut self) -> Self { // <-- mutable borrow Foo(self.0.clone()) } } 

I know that the compiler will not automatically implement Send and Sync for my type; but I'm interested in what I could safely implement manually. I think:

  • It should be able to implement Sync : having an invariable link to Foo will not allow us to do anything with this (because we can only call my_clone() via a mutable / exclusive link). And without doing anything, nothing can go wrong, right?

  • You cannot implement Send : we can clone our Foo in the main thread (before the start of another thread) to get a second object. Now both objects exchange some memory (reference counter stored in Cell<usize> ). If I could now send one of these objects to another thread, both threads would have ownership of Foo , referring to the same memory. Thus, both objects can simultaneously call my_clone() , which will lead to simultaneous, unsynchronized, mutable access to the reference counter (data race).

Is this reasoning right or am I missing something?

+6
source share
1 answer

I know that the compiler will not automatically implement Send and Sync for my type.

In fact, the compiler automatically implements Send and Sync for you only when it can determine that it is safe.

This small program:

 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)); } 

Only errors on the line Cell::new(0) , Automatic make up Sync , because all its fields are Sync .


As for Foo , Rc is neither Sync nor Send , so really the compiler will not implement it for you.

Could Foo be Sync ?

I believe 1 so. Until another operation is added to the module that works with immutable links. Now or in the future.

Could Foo be Send ?

I agree with your conclusion, but I think you skipped another method that modifies Cell : drop .

So you seem to have come up with the Sync type, not Send , using the basic Send type, not Sync . It may be my botanical meaning, I find it pretty funny :)

1 When working with unsafe code, I'm never sure of anything. It's very easy to fool yourself into thinking that something is safe, simply because a tiny little thing avoided attention.

+4
source

Source: https://habr.com/ru/post/1014404/


All Articles