Skip to content

Instantly share code, notes, and snippets.

@algon-320
Last active August 14, 2020 02:16
Show Gist options
  • Save algon-320/6b9c07f197cfb0f810843c842fb90f4a to your computer and use it in GitHub Desktop.
Save algon-320/6b9c07f197cfb0f810843c842fb90f4a to your computer and use it in GitHub Desktop.
use core::cell::UnsafeCell;
use core::sync::atomic::{fence, spin_loop_hint, AtomicBool, Ordering};
struct SpinlockMutex<T> {
locked: AtomicBool,
data: UnsafeCell<T>,
}
struct SpinlockMutexGuard<'mtx, T> {
mutex: &'mtx SpinlockMutex<T>,
}
impl<T> SpinlockMutex<T> {
pub const fn new(data: T) -> Self {
Self {
locked: AtomicBool::new(false),
data: UnsafeCell::new(data),
}
}
pub fn lock(&self) -> SpinlockMutexGuard<'_, T> {
while self.locked.compare_and_swap(false, true, Ordering::Relaxed) {
spin_loop_hint();
}
fence(Ordering::Acquire);
SpinlockMutexGuard { mutex: self }
}
}
unsafe impl<T> Send for SpinlockMutex<T> {}
unsafe impl<T> Sync for SpinlockMutex<T> {}
use core::ops::{Deref, DerefMut};
impl<'mtx, T> Deref for SpinlockMutexGuard<'mtx, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.mutex.data.get() }
}
}
impl<'mtx, T> DerefMut for SpinlockMutexGuard<'mtx, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<'mtx, T> Drop for SpinlockMutexGuard<'mtx, T> {
fn drop(&mut self) {
fence(Ordering::Release);
self.mutex.locked.store(false, Ordering::Relaxed);
}
}
// [dependencies]
// lazy_static = "1.4.0"
lazy_static::lazy_static! {
static ref GLOBAL_INT: SpinlockMutex<u64> = SpinlockMutex::new(0);
}
fn increment_many_times() {
for _ in 0..1000 {
let mut lk = GLOBAL_INT.lock();
*lk += 1;
}
}
fn main() {
let others = (0..1000)
.map(|_| std::thread::spawn(increment_many_times))
.collect::<Vec<_>>();
for th in others {
th.join().unwrap();
}
let lk = GLOBAL_INT.lock();
assert_eq!(*lk, 1000000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment