Skip to content

Add RwLockReadGuard::upgrade method to obtain RwLockWriteGuard #7282

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

Open
allevo opened this issue Apr 22, 2025 · 10 comments
Open

Add RwLockReadGuard::upgrade method to obtain RwLockWriteGuard #7282

allevo opened this issue Apr 22, 2025 · 10 comments
Labels
A-tokio Area: The main tokio crate C-feature-request Category: A feature request. M-sync Module: tokio/sync

Comments

@allevo
Copy link

allevo commented Apr 22, 2025

Is your feature request related to a problem? Please describe.
I have a procedure that can be split into two parts:

  • Calculate the changes: this takes time and requires only read permission
  • Apply the changes: this is fast and requires write permission

Those operations rely on the same locked data. I cannot guarantee the calculated changes are valid before acquiring the write guard because the thread can be yielded in the middle.

let read_guard = my_rw_lock.read();
let delta = calculate_delta(&read_guard);
drop(read_guard);

my_async_fn().await; // possible yield

let write_guard = read_guard.upgrade().await;
apply_delta(&write_guard, delta);
drop(write_guard);

Describe the solution you'd like
I would like to have a way to upgrade the read guard to a write guard, so I can write something like:

let read_guard = my_rw_lock.read();
let delta = calculate_delta(&read_guard);
let write_guard = read_guard.upgrade().await;
apply_delta(&write_guard, delta);
drop(write_guard);

In this way, I'm sure the delta is valid.

Describe alternatives you've considered
I haven't found any solutions

Additional context

@allevo allevo added A-tokio Area: The main tokio crate C-feature-request Category: A feature request. labels Apr 22, 2025
@sfackler
Copy link
Contributor

That style of API will deadlock if there are there are ever 2 concurrent tasks trying to upgrade. A special "upgradable read" mode can avoid that: https://docs.rs/parking_lot/latest/parking_lot/type.RwLock.html#method.upgradable_read.

@Darksonn Darksonn added the M-sync Module: tokio/sync label Apr 22, 2025
@Darksonn
Copy link
Contributor

Tokio's rwlock is implemented using a semaphore. I don't think we can implement upgradable reads with a semaphore, and we're not going to completely change the implementation just for this.

@allevo
Copy link
Author

allevo commented Apr 22, 2025

Hi @sfackler. If you want we can discuss about the API in order to avoid deadlock (I wrote it without any special experience in tokio lib). I don't understand what do you want to say with that link. Can you elaborate more?

Thanks @Darksonn for your reply. I understood the complexity of this task and your reply highlight a possible blocker for this implementation. Do you any suggestion how I can implement it? (with tokio or other libraries).

@sfackler
Copy link
Contributor

Can you elaborate more?

What happens if two threads currently hold a read lock, and both decide that they want to upgrade to a write lock?

@allevo
Copy link
Author

allevo commented Apr 22, 2025

What happens if two threads currently hold a read lock, and both decide that they want to upgrade to a write lock?

The upgrade should fail imho.

@Darksonn
Copy link
Contributor

Darksonn commented Apr 23, 2025

Making the upgrade fail would also require tracking new information, and I don't think we should make the RwLock type larger for this feature either.

@nevakrien
Copy link

I think you could implement this with a compare exchange.

Since the only time you are allowed to aquire the lock is when no one else is holding it that would mean that the number of readers is 1. You then want to do

Compare_exchange(cond,1,-1)

If this succeeds then you have unique access and of it fails the error can give back your read lock.

@nevakrien
Copy link

made a rough draft of how this can look like
#7284

@Darksonn
Copy link
Contributor

Yes, it's possible to implement try_upgrade, but it doesn't really help with the use-case that this issue proposes to add the method for. In fact, I think it's pretty rare that try_upgrade is useful, because even if you only have one user it still has no mechanism to wait for readers to go away.

@nevakrien
Copy link

I see ur point, the waiting mechanism itself is not gonna be an easy change.
so this thing is likely too neich to implement although you could do it if it was needed.

maybe a seprate struct? maybe in another crate? that does this weird neich thing of letting u upgrade a lock.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate C-feature-request Category: A feature request. M-sync Module: tokio/sync
Projects
None yet
Development

No branches or pull requests

4 participants