Atomic `Arc::swap`?


#1

I’m porting some code from Go. This code uses multiple pointers to one atomic pointer, that can be swapped from any thread at any time. In Rust terms it would be something like:

struct Logger {
   shared_atomic_handler * mut AtomicPtr<Handler>
}

As Go has GC, there’s no problem with ownership on swap of AtomicPtr, as both new and old Handler instance will be alive as long as needed and GCed when not referenced anymore by anyone. In Rust one could do atomic swap on the AtomicPtr, but there’s no way to know when (if ever) the old Handler instance is OK to free.

However, I see no way to port it to Rust, that wouldn’t require me to use spinlock/mutex (which is undesirable, especially in hot path of the logging library that I’m porting).

It seems to me that if Arc had an atomic swap, the problem would be solved with:

struct Logger {
   shared_atomic_handler Arc<Arc<Handler>>
}

impl Logger {
   fn swap(&self, new_handler : Arc<Handler>) {
       Arc::swap(& *self.shared_atomic_handler, &new_handler)
   }
}

The Arc::swap would convert:

          A ----> N
   A -\
   A ---> A ----> O
   A --/      /
            A-

where A is Arc, O - old (previous) handler (that has a additional reference), and N - new handler into:

          A -\ /- N
   A -\       X
   A ---> A -/ \- > O
   A --/      /
            A-

As you can see total number of references for N and O does not change, so could this be an atomic operation (swap on Arc’s inner pointer maybe)?

If not, does anyone see any good solution to my original porting problem?


#2

I recently added this to the crossbeam crate! https://github.com/aturon/crossbeam/blob/master/src/sync/arc_cell.rs


#3

Thank you so much! You’ve just unblocked this for me.

Still, the question remains - does it make sense to have in stdlib? Is it even doable and make sense?


#4

It’s definitely a possibility.