Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Greedy read lock for RwLock #70

Open
Visic opened this issue Nov 14, 2019 · 4 comments
Open

Greedy read lock for RwLock #70

Visic opened this issue Nov 14, 2019 · 4 comments

Comments

@Visic
Copy link

Visic commented Nov 14, 2019

I would like to be able to do a greedy readlock on the RwLock.

What I mean by a "greedy" readlock, is that when I call "read" on the RwLock, it increments the reader count (locking out future writers), but the read guard it returns will spin in the deref so that the data access is still safe.

I don't know if this would be of interest to anyone else, but I have hacked away at the RwLock implementation to fit my needs: https://gist.github.com/Visic/5c672c750e1a6e16590d9cd7dd11d1c8

My specific use case is that I need to be able to lock in the current state when some event happens (without blocking that thread), and then leaving it up to the future consumers of the lock to deal with the potential waiting. This also has an added benefit that waiting at that point is less likely, since if the write lock had been taken before, the writer might have finished before you ever actually access the data.

A further improvement could be to implement some sort of "try_deref" on the readlock, so that the readers aren't Forced to wait if they want to poll for the final result.

If this isn't of interest for this crate, please feel free to close the issue.

@ghost
Copy link

ghost commented Oct 31, 2020

My specific use case is that I need to be able to lock in the current state when some event happens (without blocking that thread)

I’m interested in potentially implementing this, but I don’t think I’m understanding the use case completely. Looking at the gist, the read implementation doesn’t lock in the current state of the protected data until the Deref finishes spinning (since there may still be a writer mutating the data). Is the idea here just to signal early that future writers should wait so a reader is less likely to wait?

@Visic
Copy link
Author

Visic commented Nov 3, 2020

You are essentially correct, the most important part of this is to signal that future writers need to wait, however in my system this approach serves a few purposes.

  1. Relatively efficient reading:: When I take a readlock I don't tend to use that state right away, so there is generally time for the active writer to finish up, and my readers won't actually spin when they go to use the data.
  2. Locking in the state at any time:: This includes if I am still currently updating it and goes hand-in-hand with my first point.
  3. Not blocking to get the value until I actually need to use it:: This also goes hand-in-hand with my first point.

To put this into a little context, I have an actor system where each actor exposes some "state". There are events in the system which require me to lock in various actor's states as quickly as possible, and pass those locks onto other actors to be consumed (in their own threads) whenever they can get around to it.

Here is an updated gist with the code I am currently using in production: https://gist.github.com/Visic/3c951421b1e15c809f207dfa34bff30e

Edit: This approach has been working wonderfully for me for almost a year now. I am happy to answer questions, but I might need to be a little vague as to the actual system I am working on.

@ghost
Copy link

ghost commented Nov 7, 2020

Awesome, thanks for the explanation! I guess I'm still a little confused on this part:

Locking in the state at any time:: This includes if I am still currently updating it and goes hand-in-hand with my first point.

Based on the implementation you have in the gist and your description, I don't fully understand what you mean by "locking in the state", since a current writer isn't prevented from writing after read returns but before deref returns. It's might just be that a different API is needed for this, but it seems like this breaks the semantics of read.

@Visic
Copy link
Author

Visic commented Nov 10, 2020

I think I understand your confusion, in the new gist you'll see I removed the write guard in favor of a "try_update" method, meaning that a write lock can only be used for a single update operation. This equates to "locking in the state" since the only write that can be performed after a read lock is requested, is one that is already in progress.

I'm sure the same could be done if I gave out write locks still by only using them for a single update before dropping the lock, so with the original interface, that point is really more about how I was using it rather than the actual guarentees, and it would be more accurate to just say that a new writer couldn't be given out once a reader was requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants