rustrwlock

Reader Writer Lock Pattern in RUST


I have a scenario like this : Rust Playground

This is a common pattern in C++. How do I solve this in RUST?


Solution

  • You seem to be confused about a few things. Let me try to clarify.

    With that out of the way, what you want to do is put the data in your type into the lock. You can do this with a tuple, but a better idea would be a private "inner" type, like this:

    struct Container {
        lock: RwLock<ContainerInner>,
    }
    
    struct ContainerInner {
        pub data1: u32,
        pub data2: u32,
    }
    

    Now, you want to take &self instead.

    If you have methods that need to operate on the data in ContainerInner because you call them from multiple locations, you can simply put them on ContainerInner instead, like this:

    impl Container {
        pub fn update_date(&self, val1: u32, val2: u32) {
            self.lock.write().unwrap().complex_mutation(val1, val2);
        }
    }
    
    impl ContainerInner {
        fn complex_mutation(&mut self, val1: u32, val2: u32) {
            self.data1 = val1;
            self.data2 = val2;
        }
    }
    

    Note that if you have a &mut self then you don't actually need to lock; RwLock::get_mut() allows you to get a &mut to the inner value if you have a &mut to the lock without locking because having an &mut to the lock is a static guarantee that the value isn't shared.

    If it helps you conceptually, & and &mut work kind of like RwLock's read() and write() respectively -- you can have many & or a single &mut, and if you have a &mut you can't have a &. (This is somewhat simplified, but you get the idea.) Unlike with runtime locks, the Rust compiler checks that these are used correctly at compile time, which means no runtime checks or locks are needed.

    So you could add a method like this:

    impl Container {
        pub fn update_date_mut(&mut self, val1: u32, val2: u32) {
            self.lock.get_mut().unwrap().complex_mutation(val1, val2);
        }
    }
    

    This is exactly the same as the other method except we take &mut self which allows us to use get_mut() in place of write(), bypassing the lock. The compiler will not let you call this method unless it can prove the value isn't shared, so it is safe to use if the compiler lets you use it. Otherwise, you need to use the other method, which will lock.