Skip to content

Instantly share code, notes, and snippets.

@jsimmons
Created January 4, 2020 22:31
Show Gist options
  • Save jsimmons/41a63923aeac1e8e7af9236e7def67de to your computer and use it in GitHub Desktop.
Save jsimmons/41a63923aeac1e8e7af9236e7def67de to your computer and use it in GitHub Desktop.
Dont use this please
use std::cell::UnsafeCell;
use std::sync::atomic::{spin_loop_hint, AtomicBool, AtomicU32, Ordering};
use std::sync::{Barrier, Mutex};
use std::ops::{Deref, DerefMut};
use std::thread;
use parking_lot;
struct LockInner(AtomicBool);
const LOCKED: bool = true;
const UNLOCKED: bool = false;
impl LockInner {
fn new() -> LockInner {
LockInner(AtomicBool::new(UNLOCKED))
}
#[inline]
fn lock(&self) {
let mut i = 0;
while self.0.load(Ordering::Relaxed) == LOCKED
|| self.0.swap(LOCKED, Ordering::Acquire) == LOCKED
{
spin_loop_hint();
if i == 16 {
i = 0;
std::thread::sleep_ms(1);
}
i += 1;
}
}
#[inline]
fn unlock(&self) {
self.0.swap(UNLOCKED, Ordering::Release);
}
}
struct Spinlock<T> {
lock: LockInner,
data: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for Spinlock<T> {}
unsafe impl<T: Send> Sync for Spinlock<T> {}
struct SpinlockGuard<'a, T: 'a> {
lock: &'a Spinlock<T>,
}
impl<'mutex, T> SpinlockGuard<'mutex, T> {}
impl<T> Drop for SpinlockGuard<'_, T> {
fn drop(&mut self) {
self.lock.lock.unlock();
}
}
impl<T> Deref for SpinlockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T> DerefMut for SpinlockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T> Spinlock<T> {
pub fn new(t: T) -> Spinlock<T> {
Spinlock {
lock: LockInner::new(),
data: UnsafeCell::new(t),
}
}
pub fn lock(&self) -> SpinlockGuard<'_, T> {
self.lock.lock();
SpinlockGuard { lock: &self }
}
}
fn main() {
//let counter = Box::new(Spinlock::new(0));
//let counter: &'static Spinlock<u32> = Box::leak(counter);
//let counter: &'static parking_lot::Mutex<u32> = Box::leak(Box::new(parking_lot::Mutex::new(0)));
let counter: &'static Spinlock<u32> = Box::leak(Box::new(Spinlock::new(0)));
//let counter: &'static AtomicU32 = Box::leak(Box::new(AtomicU32::new(0)));
let barrier = Box::new(Barrier::new(1));
let barrier: &'static Barrier = Box::leak(barrier);
let mut spawned_threads = Vec::new();
for _ in 0..7 {
spawned_threads.push(thread::spawn(move || {
barrier.wait();
for _ in 0..8000000 {
let mut lock = counter.lock();
*lock = lock.wrapping_add(1);
}
}));
}
barrier.wait();
for _ in 0..8000000 {
let mut lock = counter.lock();
*lock = lock.wrapping_add(1);
}
for handle in spawned_threads {
handle.join().unwrap();
}
println!("Counted to {}", *(counter.lock()));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment