Compiling playground v0.0.1 (/playground)
error[E0277]: `dyn Foo` cannot be shared between threads safely
--> src/lib.rs:9:5
|
9 | task::spawn_blocking(|| {
| ^^^^^^^^^^^^^^^^^^^^ `dyn Foo` cannot be shared between threads safely
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.7.1/src/task/blocking.rs:138:28
|
138 | F: FnOnce() -> R + Send + 'static,
| ---- required by this bound in `spawn_blocking`
|
= help: the trait `Sync` is not implemented for `dyn Foo`
= note: required because of the requirements on the impl of `Sync` for `Unique<dyn Foo>`
= note: required because it appears within the type `Box<dyn Foo>`
= note: required because of the requirements on the impl of `Sync` for `Unique<Box<dyn Foo>>`
= note: required because it appears within the type `alloc::raw_vec::RawVec<Box<dyn Foo>>`
= note: required because it appears within the type `Vec<Box<dyn Foo>>`
= note: required because of the requirements on the impl of `Sync` for `Arc<Vec<Box<dyn Foo>>>`
= note: required because of the requirements on the impl of `Send` for `&Arc<Vec<Box<dyn Foo>>>`
= note: required because it appears within the type `[closure@src/lib.rs:9:26: 13:6]`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`
To learn more, run the command again with --verbose.
The meaning of Sync is "it is safe to immutably access this value from several threads in parallel". Since an Arc can be cloned to get multiple shared handles to the same value, and each clone could be in a different thread, it's not safe to send an Arc across threads unless the inner value is Sync.
Okay thank you. I thought that it is enough to not mutate the value inside the Arc. So I would need to wrap the Vec in a, e.g., Mutex even if I don't want to mutate the Vec any further?
Yes, wrapping it in a mutex would let you avoid the Sync requirement because then only one thread can access it at the time. Though it would be simpler to just require Sync if the contents allow that.
I know the example was only somthing quickly put together. BTW is there an easy to convert Arc<Vec<T>> to Arc<[T]> without copying the vec's contents? There is into_boxed_slice() on Vec and you could do something with pointers and unsafe (probably) but that seems not preferable for me.
No, there's no way to do that conversion without copying the data over because the way they are represented in memory is different. An Arc<Vec<T>> has two allocations, whereas Arc<[T]> has only one.
Oh sorry mistyped. I wanted to know if there is a possibility to convert a Vec<T> into an Arc<[T]>. AFAIK both have one indirection so it should be possible to reuse the allocated memory from the Vec for the Arc, right?
Arc<[T]> stores the reference counter at the start of the allocation and a Vec<T> leaves no space for that
Vec<T> has a spare capacity to push other elements without reallocating, Arc<[T]> can't have that. This also applies for .into_boxed_slice(), it will reallocate if vec.len() != vec.capacity().
If that were the case different Arcs wouldn't be able to update the same counter. You could technically store the reference counter in a separate allocation (I think shared_ptr allows that?), however that's not what the stdlib's implementation does.