1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::*;
/// a primitive for mutual exclusion that spins in a loop
pub struct SpinLock<T> {
locked: AtomicBool,
value: UnsafeCell<T>,
}
pub struct Guard<'a, T> {
lock: &'a SpinLock<T>,
}
impl<T> SpinLock<T> {
/// Creates a new spinlock.
///
/// # Examples
///
/// ```
/// use lib_wc::sync::SpinLock;
///
/// let spinlock = SpinLock::new(0);
///
/// {
/// let mut guard = spinlock.lock();
/// *guard += 1;
/// } // The guard is dropped here, unlocking the mutex
///
/// {
/// let mut guard = spinlock.lock();
/// *guard += 1;
/// } // The guard is dropped here, unlocking the mutex
///
/// assert_eq!(*spinlock.lock(), 2);
/// ```
pub fn new(value: T) -> Self {
Self {
locked: AtomicBool::new(false),
value: UnsafeCell::new(value),
}
}
/// Acquires a lock on the spinlock, spinning the current thread in a loop until it is able to do so.
///
/// This function returns a `Guard` which will release the lock when dropped.
///
/// # Examples
/// ```
/// use lib_wc::sync::SpinLock;
///
/// let spinlock = SpinLock::new(0);
///
/// {
/// let mut guard = spinlock.lock();
/// *guard += 1;
/// } // The guard is dropped here, unlocking the mutex
///
/// {
/// let mut guard = spinlock.lock();
/// *guard += 1;
/// } // The guard is dropped here, unlocking the mutex
///
/// assert_eq!(*spinlock.lock(), 2);
/// ```
pub fn lock(&self) -> Guard<T> {
while self.locked.swap(true, Acquire) {
std::hint::spin_loop();
}
Guard { lock: self }
}
}
// T doesn't need to be sync because only one thread will have access to it at a time
unsafe impl<T> Sync for SpinLock<T> where T: Send {}
impl<T> Deref for Guard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// Safety: the existence of this guard guarantees
// that we have exclusively locked the lock
unsafe { &*self.lock.value.get() }
}
}
impl<T> DerefMut for Guard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
// Safety: the existence of this guard guarantees
// that we have 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);
}
}
#[cfg(test)]
mod tests {
use crate::concurrent::sync::SpinLock;
#[test]
fn test_spinlock() {
let x = SpinLock::new(Vec::new());
std::thread::scope(|s| {
s.spawn(|| x.lock().push(1));
s.spawn(|| {
let mut g = x.lock();
g.push(2);
g.push(2);
});
});
let g = x.lock();
assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]);
}
#[test]
fn test_multiple_threads() {
let x = SpinLock::new(Vec::new());
std::thread::scope(|s| {
s.spawn(|| x.lock().push(1));
for _ in 0..100 {
s.spawn(|| x.lock().push(1));
}
});
assert_eq!(x.lock().len(), 101);
}
}