Skip to content

Instantly share code, notes, and snippets.

@preinpost
Created May 5, 2024 12:47
Show Gist options
  • Save preinpost/89b80ba19a22ed5575f15a06daddd0e5 to your computer and use it in GitHub Desktop.
Save preinpost/89b80ba19a22ed5575f15a06daddd0e5 to your computer and use it in GitHub Desktop.
Rust Atomics and Locks - ch4
use std::cell::UnsafeCell;
use std::fmt::{Debug, Formatter, Pointer};
use std::ops::{Deref, DerefMut};
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::{Acquire, Release};
use std::thread;
pub struct SpinLock<T> {
locked: AtomicBool,
value: UnsafeCell<T>,
}
unsafe impl<T> Sync for SpinLock<T> where T: Send {}
pub struct Guard<'a, T> {
lock: &'a SpinLock<T>,
}
unsafe impl<T> Sync for Guard<'_, T> where T: Sync {}
impl<T> SpinLock<T> {
pub const fn new(value: T) -> Self {
Self {
locked: AtomicBool::new(false),
value: UnsafeCell::new(value),
}
}
pub fn lock(&self) -> Guard<T> {
while self.locked.swap(true, Acquire) {
std::hint::spin_loop();
}
Guard { lock: self }
}
}
impl<T> Deref for Guard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.value.get() }
}
}
impl<T> DerefMut for Guard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.value.get() }
}
}
impl<T> Drop for Guard<'_, T> {
fn drop(&mut self) {
self.lock.locked.store(false, Release);
}
}
fn main() {
let x = SpinLock::new(Vec::new());
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();
dbg!(&g.as_slice());
assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment