Amanieu / parking_lot

Compact and efficient synchronization primitives for Rust. Also provides an API for creating custom synchronization primitives.
Apache License 2.0
2.77k stars 217 forks source link

Add `with_upgraded` API to upgradable read locks #386

Closed Jules-Bertholet closed 1 year ago

Jules-Bertholet commented 1 year ago

RwLockUpgradableReadGuard::upgrade takes the guard by value, so there is currently no way to turn an &mut to an upgradable guard into an &mut to the underlying data.

This PR remedies that with a closure-based API. RwLockUpgradableReadGuard::with_upgraded() takes a mutable reference to an upgradable guard, and:

1) Upgrades the lock 2) Retrieves an &mut to the underlying data 3) Passes the &mut to a user-provided closure 4) Downgrades the lock back to an upgradable read 5) Returns the result of the closure.

Amanieu commented 1 year ago

This API looks fine, however I'm generally not very happy with upgradable locks and am considering deprecating them: you almost always get better performance by just:

Can you explain your use case for upgradable locks and possibly consider moving away from them?

Jules-Bertholet commented 1 year ago

My use case: I have a worker thread, that's managing an object/resource. This thread regularly reads from the object, and occasionally writes. In addition, I have a UI thread that is monitoring the object. The UI thread needs to read from the object after every modification (to display the new state), and potentially on a few other occasions as well. No thread, other than the worker, should ever need write access.

My current design, is to shove my object into an Arc<RwLock<Object>>. The worker thread keeps around a &mut ArcRwLockUpgradableReadGuard<Object>, which it can pass around to various functions as needed. When the worker needs to perform a write, it uses with_upgradable. Once the write operation is complete, it uses a channel to notify the UI, which then briefly takes a standard read lock to do what it needs.