once_cell icon indicating copy to clipboard operation
once_cell copied to clipboard

Provide non blocking subset of sync::OnceCell for no_std

Open matklad opened this issue 6 years ago • 4 comments
trafficstars

OnceCell::get and OnceCell:: set could work without blocking, so we should support these APIs in no std. Note that we intentionally do not want to implement no_std blocking via spinning, see https://www.reddit.com/r/rust/comments/cy910u/comment/eyrfmna for rationale.

matklad avatar Sep 01 '19 20:09 matklad

Thinking of it, looks like even set can't be lock, in general? You need to atomically set both the is_completed state and the value, and you can only do that if you can pack both into a single word.

You can do that if you heap-allocate the value, but that again needs std.

matklad avatar Sep 02 '19 08:09 matklad

Thinking of it, looks like even set can't be lock, in general? You need to atomically set both the is_completed state and the value, and you can only do that if you can pack both into a single word.

Would one atomic with three states not be enough?

pub struct OnceCell<T> {
    status: AtomicUsize,
    value: UnsafeCell<Option<T>>,
}

pub fn set(&self, value: T) -> Result<(), T> {
    match self.state.load(Ordering::Relaxed) {
        UNINITIALIZED => {
            let old = self.state.compare_and_swap(UNINITIALIZED, RUNNING, Ordering::Relaxed);
            if old != UNINITIALIZED {
                // Another thread must have initialized the cell just now, or is in the process of initializing it.
                Err(value)
            }
            let slot = unsafe { &mut *self.inner.get() };
            *slot = Some(value);
            self.state.store(INITIALIZED, Ordering::Release);
            Ok(())
        },
        RUNNING | INITIALIZED => Err(value),
    }
}

I suppose that if the initializing thread gets suspended while the state is RUNNING, all threads are out of luck until it can continue, but don't really see other problems yet.

pitdicker avatar Oct 19 '19 20:10 pitdicker

Hm, that’s interesting!

I think we perhaps need two methods with set-like semantics: one that might block, but guarantees that the cell is initialized (maybe even returns an &T), and one that does not block, bit also does not guarantee that the cell is initialized.

matklad avatar Oct 19 '19 21:10 matklad

Changing the current set to not block would be a difficult change, as code currently could call get_unchecked after a set and expect it to be safe.

A non blocking set would mean the first get has to be used in a loop or something until it succeeds. I see not blocking as less then optimal, but suppose such a new method can unlock some uses and support no_std.

👍 to have set return &T

pitdicker avatar Oct 20 '19 05:10 pitdicker

This is now more or less availble in the race module

matklad avatar Oct 22 '22 19:10 matklad