pub mod slop_mutex { use core::cell::UnsafeCell; use core::hint::spin_loop; use core::ops::{Deref, DerefMut}; use core::sync::atomic::{AtomicBool, Ordering}; pub struct SpinMutex { locked: AtomicBool, data: UnsafeCell, } // Safety: SpinMutex is Sync if T is Send. // We use AtomicBool to synchronize access to the UnsafeCell. unsafe impl Sync for SpinMutex {} pub struct SpinMutexGuard<'a, T> { lock: &'a SpinMutex, } impl SpinMutex { pub const fn new(data: T) -> Self { Self { locked: AtomicBool::new(false), data: UnsafeCell::new(data), } } pub fn lock(&self) -> SpinMutexGuard<'_, T> { // Attempt to swap false -> true. // If it fails, we "spin" (loop) until it succeeds. while self .locked .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) .is_err() { // Signal to the CPU that we are in a spin loop to save power/resources spin_loop(); } SpinMutexGuard { lock: self } } } impl<'a, T> Deref for SpinMutexGuard<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { // Safety: We hold the lock, so we have exclusive access to the data. unsafe { &*self.lock.data.get() } } } impl<'a, T> DerefMut for SpinMutexGuard<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { // Safety: We hold the lock, so we have exclusive access to the data. unsafe { &mut *self.lock.data.get() } } } impl<'a, T> Drop for SpinMutexGuard<'a, T> { fn drop(&mut self) { // Set the lock back to false. // Release ordering ensures our changes to the data are visible to the next locker. self.lock.locked.store(false, Ordering::Release); } } } use std::{thread, time::Duration}; fn main() { static SLOP_COUNTER: slop_mutex::SpinMutex = slop_mutex::SpinMutex::new(0); let handle = thread::spawn(|| { println!("I'm on the other thread..."); for _ in 0..100000 { let mut guard = SLOP_COUNTER.lock(); *guard += 1; thread::sleep(Duration::from_micros(1)); } println!( "I finished 100000 counts, the current count is {}", *SLOP_COUNTER.lock() ); }); println!("And I'm Javert"); for _ in 0..100000 { let mut guard = SLOP_COUNTER.lock(); *guard += 1; thread::sleep(Duration::from_micros(1)); } println!( "I finished 100000 counts, the current count is {}", *SLOP_COUNTER.lock() ); _ = handle.join(); }