SpinLock implementation
Naive unsafe implementation
#![allow(unused)] fn main() { use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::{Acquire, Release}; use std::cell::UnsafeCell; pub struct SpinLockUnsafe<T> { locked: AtomicBool, value: UnsafeCell<T>, } unsafe impl<T> Sync for SpinLockUnsafe<T> where T: Send {} impl<T> SpinLockUnsafe<T> { pub const fn new(value: T) -> Self { Self { locked: AtomicBool::new(false), value: UnsafeCell::new(value), } } pub fn lock(&self) -> &mut T { while self.locked.swap(true, Acquire) { std::hint::spin_loop(); } unsafe { &mut *self.value.get() } } /// Safety: The &mut T from lock() must be gone! /// (And no cheating by keeping reference to fields of that T around!) pub unsafe fn unlock(&self) { self.locked.store(false, Release); } } }
Better safe version and much easier to use
With the help of a Guard
trick we let unlock
be triggered during a drop
on a Guard
.
Interesting pattern.
#![allow(unused)] fn main() { use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::{Acquire, Release}; use std::cell::UnsafeCell; use std::ops::{Deref, DerefMut}; /// To be able to provide a fully safe interface, we need to tie the unlocking operation to /// the end of the &mut T. We can do that by wrapping this reference in our own type that /// behaves like a reference, but also implements the Drop trait to do something when it is dropped. /// /// Such a type is often called a guard, as it effectively guards the state of the lock, /// and stays responsible for that state until it is dropped. pub struct Guard<'a, T> { lock: &'a SpinLock<T>, } pub struct SpinLock<T> { locked: AtomicBool, value: UnsafeCell<T>, } unsafe impl<T> Sync for SpinLock<T> where T: Send {} impl<T> SpinLock<T> { pub const fn new(value: T) -> Self { Self { locked: AtomicBool::new(false), value: UnsafeCell::new(value), } } pub fn lock(&self) -> Guard<T> { while self.locked.swap(true, Acquire) { std::hint::spin_loop(); } Guard { lock: self } } } impl<T> Deref for Guard<'_, T> { type Target = T; fn deref(&self) -> &T { // Safety: The very existence of this Guard // guarantees we've exclusively locked the lock. unsafe { &*self.lock.value.get() } } } impl<T> DerefMut for Guard<'_, T> { fn deref_mut(&mut self) -> &mut T { // Safety: The very existence of this Guard // guarantees we've exclusively locked the lock. unsafe { &mut *self.lock.value.get() } } } impl<T> Drop for Guard<'_, T> { fn drop(&mut self) { self.lock.locked.store(false, Release); } } }