Why does `Arc <T>` require that T be both `Send` and` Sync` in order to be `Send` /` Sync` itself?

Arc<T> documentation says:

 impl<T> Sync for Arc<T> where T: Send + Sync + ?Sized impl<T> Send for Arc<T> where T: Send + Sync + ?Sized 

An Arc allows multiple threads to access the underlying T at the same time via an &T immutable link. This is safe until T can be changed in an unsynchronized manner via &T This is true for all types with "inherited variability" (almost all types) and false for those with unsynchronized "internal variability" (for example, RefCell , ...).

As far as I understand, Send binding is not required here. For example, I think my shared artificial type, which implements Sync but not Send in Arc , is safe.

Finally, &T itself also does not have this binding! In the documentation for Send and Sync we find:

 impl<'a, T> Send for &'a T where T: Sync + ?Sized impl<'a, T> Sync for &'a T where T: Sync + ?Sized 

And since Arc<T> allows the same access to T as &T , I don’t understand why Arc<T> has an additional Send binding. Why is this?

+6
source share
1 answer

I believe this is because Arc owns the value that it contains, and therefore is responsible for removing it.

Consider the following sequence:

  • In stream 1, a value of type T . This is not Send , which means that transferring this value to another thread is unsafe.
  • This value is moved to the Arc descriptor.
  • The descriptor clone is sent to stream 2.
  • The handle stored in stream 1 is discarded.
  • The handle stored in stream 2 is discarded. Since this is the last handle, it assumes full ownership of the stored value and omits it.

And also we moved a value of type T from one thread to another, violating memory security.

&T does not require Send , because deleting &T never allows you to abandon the base value.

Addition . As an example of a type where this would be a problem, consider a type of type struct Handle(usize); which is supported by a local array of stream resources. If the Drop implementation for this type is launched in the wrong thread, this will result in it either making access outside the boundaries (where it is trying to destroy a resource that does not exist in this thread) or it will destroy the resource that is still in use.

+8
source

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


All Articles