Is there a synchronization primitive (in sync or async Rust) that blocks on an Arc until it has just the single reference (and no weak references)? There are a few things that work similarly:
You can build something like this with a condition variable (though only in the synchronous world, I guess watch does something similar in tokio).
You can create a MPSC channel, block on the receiver and wait until you read None.
Arc itself is not a synchronization primitive, it is a resource management construction. are you looking for counting semaphores? I think there's a Semaphore in tokio. however, I don't think there's one in std
Arc does (implicitly) establish synchronize-with relationships in some cases (due to atomic operations with corresponding memory orderings). For example, I believe that if Arc::try_unwrap succeeds, it is guaranteed that any previous droppings of the Arc clones in other threads happen-before the successful try_unwrap call.[1] So there is some synchronization of concurrent threads taking place.
However, …
… I don't think that is possible (with the existing Arc) because that might make dropping the Arc more slow (as the drop handler would need to unpark any waiting threads or wakeup any waiting tasks, respectively). Adding such a feature would be a performance regression, I guess.[2]
(But I'm not sure on all this, so I'm happy if someone else could confirm this or correct me.)
I think this needs to be the case due to Rust's strict aliasing rules: You must not be able to obtain mutable/exclusive access if there may still exist a shared reference somewhere. ↩︎
And a performance regression of the std lib would be considered a breaking change which is not allowed to happen due to stability guarantees. ↩︎
What if there was some Arc-like object where we accept slower drops? I'm wondering about an API for DMAs. I thought something like this was mentioned and dismissed in withoutboats' post but I can't find it.
I think it's possible to implement something like this (but it wouldn't be compatible with APIs that take Arcs). Not sure if something like this already exists, or which existing synchronization primitives could be used to emulate this.
I mean, it would be trivially possible to implement this using mutexes and condition variables(edit: or mutexes and notifies in the async case), but that might be pretty inefficient. There should be a better way.
If there's only one thread waiting for mut access (and if there's more than one the problem doesn't really make sense) you could store that thread's handle inside the Arc (alongside whatever data) and call unpark on it (after) any of the other threads drop it. The mut-interested thread then just loops doing get_mut with park on failure.