Send reference counted objects together to another thread, without atomics

I'm writing an async application with async-await. The intention is to use reference counters within each task, and they will stay on only one thread at a time and will never go outside of that task. I believe this is a quite common use case for async programs, but what rust provides isn't ideal:

  • Rc isn't Send at all. Of course we can create a new thread for each task, but that defeats the purpose of the async scheduler.
  • Arc will always use an atomic counter. Worse, usually we'll need to mutate the shared object and end up using Arc<Mutex<T>>. Neither Arc nor Mutex should be required because no synchronization happens.
  • Use an arena allocator. But even if the allocator supports deallocation, fragmentation over long running tasks can still be a problem (unless we come up with an allocator as good as jemalloc).

The last idea I have is to create a master object that contains an id.

struct Master {
    id: usize,
}
// Master: !Sync

We can create Rc-like reference counters from the master:

impl Master {
    pub fn create<T>(&self, t: T) -> RcWithId<T> {
        RcWithId {
            object: // Wrap `t` with some single-thread reference count mechanism
            id: self.id,
        }
    }
}

Each time we access the reference counted object, we require the master be available and match the id.

struct RcWithId<T> {
    object: *const T, // Some single-thread reference count mechanism
    id: usize,
}

impl<T> RcWithId<T> {
    // ...
    pub fn access<'a>(&'a self, master: &'a Master) -> &'a T {
        if self.id == master.id {
            let t = // Get the real object from `self.object`
            return t;
        }
        panic!()
    }
}

It should be possible to create a safe abstraction from this. Of course, it will be painful to deal with drop.

My question is, does this idea sound right? Is there any implementation like this (or better) already?

The Master looks like QCellOwner from the qcell crate

1 Like

Thank you for replying! Owner id looks similar indeed, but from a quick view it does not provide any sharing mechanism (you cannot clone a QCell to refer to the same object).

Yeah, QCell is more like RefCell than Rc, but similar principles apply. You could use something like QCell to build a safe version of your Rc