-
-
Notifications
You must be signed in to change notification settings - Fork 346
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
Possibly add a reentrant lock #1247
Comments
The more I think about it, the more I like the idea of extending |
@efficiosoft Hello! Thanks for trying Trio, and giving us feedback :-) The main reason I didn't add re-entrant originally was just a vague impression from more experienced folks that they're messy and not necessarily a good idea. But you're right that they're common (in fact Trio even uses I did a bit of searching, and found this interesting article: http://www.zaval.org/resources/library/butenhof1.html I'm not sure how compelling his argument is in the Trio context. All the stuff about needing to hold locks for as-little-as-possible doesn't really apply for us; we're single-threaded regardless of whether you use The argument that I do think the point that you can't use an If anyone else knows of arguments for/against reentrant locking, please post them here :-) BTW: class RLock:
def __init__(self):
self._owner = None
self._depth = 0
self._lock = trio.Lock()
async def acquire(self):
if self._owner is trio.hazmat.current_task():
self._depth += 1
else:
await self._lock.acquire()
assert self._owner is None
assert self._depth == 0
self._owner = trio.hazmat.current_task()
self._depth += 1
def release(self):
if self._owner is not trio.hazmat.current_task():
raise RuntimeError
assert self._owner is trio.hazmat.current_task()
assert self._depth >= 1
self._depth -= 1
if self._depth == 0:
self._lock.release()
self._owner = None
# to do: add trivial __aenter__/__aexit__ etc. (This could be made a bit simpler if |
Agreed, so let's make it a separate object.
You're right, relying on the implementation details is a bad idea for external code, however I thought it would be ok if the |
I found another article that I think makes a pretty good case for why In particular this point:
So the point is that The "Uncertainty about lock state" section is also particularly compelling: it makes that point that reentrant locks create new deadlock hazards, because you can release the lock and then block on some other operation, which would be fine if the lock were actually released, but with a reentrant lock then you might actually still hold the lock, which might end up preventing the thing you're waiting on from happening... |
Right, inside trio core we can do whatever; that section was just a side-comment since you said you're currently subclassing |
For the general case, this is surely true. In my particular project, I'm building a framework for running custom user-written apps and am serializing management operations for those apps (starting/stopping/removing) using a per-app lock. Removing, for instance, consists of stopping + some extra work to remove the app from the system, such as cancelling watcher tasks. It now is convenient to rely on the fact that no one can start the app between |
It sounds like a reentrant lock probably isn't a great fit for Trio core right now, so going to close this. |
Hi trio team,
First, thanks for this great and well-designed library!
I don't know whether this has already been discussed, but at least googling didn't led me to an existing issue or something.
It sometimes comes handy to have reentrant locks like they're offered by
threading
. I know that everything that can be achieved with reentrant locks can also be done without them, but it can make code paths easier and stop people from adding separate_nolock
methods all over the place.I currently use something like this:
It works great so far and cancellation semantics should be correct as well, but I'm not entirely sure. Would you like a PR with this?
Another approach would be to add a keyword-only
reentrant=False
parameter to the existingtrio.Lock
, the two checks could then be added to the existingacquire_nowait
andrelease
methods with the (tiny) overhead ofif self._rcount
inrelease()
.What do you think, is this something we want in trio?
Best regards
Robert
The text was updated successfully, but these errors were encountered: