Getting a read-only version of an Arc<RwLock<Foo>>?
Asked Answered
P

1

6

I have an Arc<RwLock<Foo>>.

Is there a way to make something out of this, on which the RwLock's write() does not exist? i.e. Is there some form of RLock which I can make from an RwLock.

Use case: I have a Foo. More than one part of my code needs to mutate the Foo (hence the RwLock), but the majority of my code must only ever have read-only access to the Foo.

Is there a way of achieving this? Or is there a way of doing this without RwLock?

Potsdam answered 24/12, 2021 at 7:43 Comment(6)
similar post: #68908591Bischoff
just return the LockGuard (even the wrapped Result) from readFacesaving
It's hard to answer without a concrete example, but you can try to not use RwLock and instead Arc::get_mut().Uigur
@ChayimFriedman unfortunately I have multiple clones of the Arc<RwLock<Foo>>, in different threads.Potsdam
@Facesaving Would this work if the "read only" reference needs to live for the life of the process? Or would it block the writers?Potsdam
@fadedbee, you need to release the lock at some point, you shouldnt have a reference to the ward (because it would be locked for the entire time, so you would not be able to write it), but you can have as much of those as you want for reading.Facesaving
R
4

Write your own struct that contains the Arc<RwLock<Foo>>.

#[derive(Clone, Debug)]
pub struct FooReadOnly(Arc<RwLock<Foo>>);

impl FooReadOnly {
    pub fn read(&self) -> LockResult<RwLockReadGuard<'_, Foo>> {
        self.0.read()
    }

}

(A fully fleshed-out version would also contain a wrapper for try_read().)

The general pattern worth noting here is: instead of your data type being visibly inside an Arc<RwLock<...>>, your public type contains the Arc. This allows much more flexibility in what kind of “handles” you can offer than exposing the Arc. This is a fairly common pattern in Rust — if you've ever used a library type that notes you can clone it and get another handle to the same thing, there's a good chance it's doing the same thing inside (if it's not actually a handle to an OS resource like a file descriptor).

If you wanted to fully hide the implementation details, you would also wrap the RwLockReadGuard — all it needs to do is implement Deref<Target = Foo> and forward that to the guard. Such wrappers can also do things like Derefing to some part of the Foo rather than an &Foo exactly.

Revengeful answered 24/12, 2021 at 16:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.