Please review my RwLock :)

⚓ Rust    📅 2026-03-03    👤 surdeus    👁️ 3      

surdeus

Info

This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: Please review my RwLock :)

I am trying to write an RwLock to understand atomics and memory ordering. This obviously a bad implementation and the very first problem that I've noticed is: If I call read and write concurrently from two separate threads, the call to write may execute between the load and store present inside read which is a problem...could you please suggest a solution for this?

also, please point out other aspects I could improve. Thanks!

use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::Relaxed;

pub struct Rw<T> {
    data: UnsafeCell<T>,
    writeable: AtomicBool,
    readable: AtomicBool,
}

unsafe impl<T> Send for Rw<T> where T: Send {}
unsafe impl<T> Sync for Rw<T> where T: Send + Sync {}

impl<T> Rw<T> {
    pub fn new(data: T) -> Self {
        Self {
            data: UnsafeCell::new(data),
            writeable: AtomicBool::new(true),
            readable: AtomicBool::new(true),
        }
    }

    pub fn read<'read>(&'read self) -> RwReadGuard<'read, T> {
        while !self.readable.load(Relaxed) {
            std::hint::spin_loop();
        }

        self.writeable.store(false, Relaxed);

        RwReadGuard { rw: self }
    }

    pub fn write<'write>(&'write self) -> RwWriteGuard<'write, T> {
        while self
            .writeable
            .compare_exchange_weak(true, false, Relaxed, Relaxed)
            .is_err()
        {
            std::hint::spin_loop();
        }

        self.readable.store(false, Relaxed);

        RwWriteGuard { rw: self }
    }
}

pub struct RwReadGuard<'read, T> {
    rw: &'read Rw<T>,
}

impl<T> Deref for RwReadGuard<'_, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.rw.data.get() }
    }
}

impl<T> Drop for RwReadGuard<'_, T> {
    fn drop(&mut self) {
        self.rw.writeable.store(true, Relaxed);
    }
}

pub struct RwWriteGuard<'write, T> {
    rw: &'write Rw<T>,
}

impl<T> Deref for RwWriteGuard<'_, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.rw.data.get() }
    }
}

impl<T> DerefMut for RwWriteGuard<'_, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *self.rw.data.get() }
    }
}

impl<T> Drop for RwWriteGuard<'_, T> {
    fn drop(&mut self) {
        self.rw.readable.store(true, Relaxed);
        self.rw.writeable.store(true, Relaxed);
    }
}

2 posts - 2 participants

Read full topic

🏷️ Rust_feed