Arc and the Send bound


#1

I am trying to create a shared data item, to be sent across threads.

To do this I want to use an Arc<Any+Send+'static>. Unfortunately, this is not Send, as Arc requires:

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

My question is: why does T need to be Sync in order for the Arc to be Send?

I explicitly do NOT want to use a Mutex or RWLock, as I do not want one threads write to be visible on another thread.


#2

Sync indicates that the value can be accessed concurrently without problems. An Arc allows you to access the value concurrently by sharing it between multiple threads.

If you don’t want one thread’s write to be visible on the other thread, then it sounds like you’re looking to give each thread its own copy. In that case, you don’t need an Arc at all.


#3

I want to give other threads a read-only view of a data item. Think of a large text or image.
So I do not care about Sync, only Send (if I understand all things correctly)


#4

Read-only views of many types are Sync, e.g. u32, Vec<u32> and HashMap<String, Vec<u32>> are all Sync (i.e. all of these can be placed directly in an Arc<...>). Mutex and RWLock allow you to get thread-safe shared mutation, so if you don’t need that, you don’t need to use them.


#5

But unfortunatly not Arc<Any+Send+'static>. If I add the Sync bound I get

error: no method named `downcast_ref` found for type
`core::any::Any + Send + Sync + 'static` in the current scope

#6

That’s a somewhat different problem. To be clear, there’s literally no way to get away from Arc having a Sync bound, it is essentially the canonical example of a type that needs that bound in order to be correct: Arc is entirely about sharing data between threads and the Sync trait describes that situation (and its safety) exactly.

The Any trait is unfortunately limited in various ways, and this sort of marker trait difficulty is one of them: life is generally easier if polymorphism via Any is avoided. Other methods for doing this sort of thing include using an enum, or using a custom trait with methods for the behaviours you need (i.e. just call the method instead of trying to downcast). We may be able to give more specific help if you post some code. :slight_smile:


#7

Yes I noticed that every time I try to use Any I run into problems.

An example is the code in this example: http://is.gd/lw1Ubq
My goal is to get this to working for arbitrary Send types, not just Strings. (So Clone could be optional as well, but then the get_mut function should not be available)
A Trait would of course be acceptable as well, but I was using Any as I would like to be able to obtain the original object later on.

An enum would obviously work, but then it cannot accept externally defined types any more.


#8

Ah I solved that problem using (&**r as &(Any + Send)).downcast_ref::<T>().

Next question: Could downcast (as used by Box) also be implemented on an Arc<Any> or is there something fundamental prohibiting that?


#9

The problem here is the + Sync, not the Arc itself: the methods are only implemented for Any + 'static and Any + Send + 'static, and there’s no subtyping/coercion from Any + Sync + Send + 'static to either of those.

Box has a custom implementation because it is able to move out of the type, i.e. Box<Any> -> Option<T>, rather than &T or &mut T, while Arc<T> can’t expose anything beyond the two reference types, and so one gets all the functionality of them via Derefing to the Send + ... type itself.


#10

Using the follwing trait and wrapper everything seems to be possible :smile:Thanks for the information you’ve provided. With this I think either I will be able to implement the trait or someone can implement it on a small wrapper.

pub trait ReoReference : Any + Send + Sync {
    fn copy(&self) -> Arc<ReoReference>;
    fn any(&self) -> &(Any + Send);
    fn mut_any(&mut self) -> &mut (Any + Send);
}

#[derive(Clone)]
pub enum ReoData {
    Integer(i64),
    Double(f64),
    Reference(Arc<ReoReference>),
}

impl ReoReference for $T {
    fn copy(&self) -> Arc<ReoReference> {
       Arc::new(self.clone())
    }
    fn any(&self) -> &(Any + Send) {
        self
    }
    fn mut_any(&mut self) -> &mut (Any + Send) {
        self
    }
}