Skip to content

Instantly share code, notes, and snippets.

@davidlopezre
Last active January 30, 2022 11:10
Show Gist options
  • Save davidlopezre/7e712ef2d8f17ebb1ffceb8431a8ba3f to your computer and use it in GitHub Desktop.
Save davidlopezre/7e712ef2d8f17ebb1ffceb8431a8ba3f to your computer and use it in GitHub Desktop.
Spin Lock Mutex implementation in Rust from "Crust of Rust: Atomics and Memory Ordering"
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::{cell::UnsafeCell, sync::atomic::AtomicBool};
use std::{thread, usize};
fn main() {
const N: usize = 100;
let data = Arc::new(Mutex::new(0));
let mut handles = Vec::with_capacity(N);
for _ in 0..N {
let data = Arc::clone(&data);
let join_handle = thread::spawn(move || {
let _ = data.with_lock(|x| {
*x = *x + 1;
*x
});
});
handles.push(join_handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(N, data.with_lock(|x| *x));
}
const LOCKED: bool = true;
const UNLOCKED: bool = false;
pub struct Mutex<T> {
locked: AtomicBool,
v: UnsafeCell<T>,
}
unsafe impl<T> Sync for Mutex<T> where T: Send {}
impl<T> Mutex<T> {
fn new(t: T) -> Mutex<T> {
Self {
locked: AtomicBool::new(UNLOCKED),
v: UnsafeCell::new(t),
}
}
fn with_lock<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
while self
.locked
.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
while self.locked.load(Ordering::Relaxed) {
std::thread::yield_now();
}
std::thread::yield_now();
}
std::thread::yield_now();
let ret = f(unsafe { &mut *self.v.get() });
self.locked.store(UNLOCKED, Ordering::Relaxed);
ret
}
}
@davidlopezre
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment