Correct bounds for `unsafe impl<T> Sync for SpinLock<T>`?

I am reading through Mara's book on atomics and locks, and in the chapter 4 they are building a primitive SpinLock (implementation is listed below).

And while implementing Sync trait, the following is emphasized:

However, since the lock can be used to send values to type T from one thread to another, we must limit this promise to types that are safe to send between threads. So, we (unsafely) implement Sync for SpinLock<T> for all T that implement Send, like this:
unsafe impl<T> Sync for SpinLock<T> where: T Send {}

So the question is, why do we need T: Send bound? What does it mean that "the lock could be used to send values from one thread to another"? I mean, only one thread owns the lock, and the only thing that shared is the mutable reference to the value (so should we require only Sync instead?). Or, otherwise, what could go wrong if this bound isn't present?

Here is implementation of the spin lock for more details:

struct SpinLock<T> {
    locked: AtomicBool,
    storage: UnsafeCell<T>,
}

unsafe impl<T> Sync for SpinLock<T> where T: Send {}

impl<T> SpinLock<T> {
    pub fn lock(&self) -> &mut T {
        while self
            .locked
            .compare_exchange_weak(false, true, Acquire, Relaxed)
            .is_err()
        {
            std::hint::spin_loop();
        }
        unsafe { &mut *self.storage.get() }
    }

    pub unsafe fn unlock(&self) {
        self.locked.store(false, Release);
    }
}

Thanks in advance!

You can move the value inside an SpinLock<Option<T>> by writing Some(value) on one thread, and using mem::swap or Option::take on another thread.

2 Likes

Thanks!

Though I wonder is there more cases in which things could go wrong, is the bound isn't there? :thinking:

In general, Send is not really about moves. It's about where you're allowed to perform mutable access. See:

2 Likes

Thanks a lot!!!

This means that sending a &SpinLock<T> implies potentially sending a &mut T, which requires T: Send. Hence the implementation of Sync for SpinLock<T> must require at least T: Send (and actually that's enough).

2 Likes