| 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<T> {
|
| locked: AtomicBool,
|
| data: UnsafeCell<T>,
|
| }
|
|
|
| // Safety: SpinMutex is Sync if T is Send.
|
| // We use AtomicBool to synchronize access to the UnsafeCell.
|
| unsafe impl<T: Send> Sync for SpinMutex<T> {}
|
|
|
| pub struct SpinMutexGuard<'a, T> {
|
| lock: &'a SpinMutex<T>,
|
| }
|
|
|
| impl<T> SpinMutex<T> {
|
| 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<usize> = 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();
|
| }
|