SmartLock deadlocks when the same thread tries to acquire the same lock twice. The deadlock is not reported as an exception, so code using SmartLock for deadlock detection can still hang on this self-recursive case.
Reproduction
from threading import Thread
from locklib import SmartLock
events = []
def target():
lock = SmartLock()
lock.acquire()
events.append('first acquire returned')
lock.acquire()
events.append('second acquire returned')
thread = Thread(target=target, daemon=True)
thread.start()
thread.join(0.3)
print(thread.is_alive())
print(events)
Current output:
True
['first acquire returned']
Expected behavior
The second acquire should not block forever. SmartLock should report this deadlock case instead of leaving the thread stuck.
Actual behavior
The second acquire never returns, and no exception is raised.
Proposed solution
Reproduce the semantics of standard Python locks by replacing the current single SmartLock class with two classes:
SmartLock: raises an exception when the same thread tries to acquire the same lock recursively. This behavior needs to be added.
SmartRLock: behaves like SmartLock in every other respect, but differs in this case: recursive acquire by the same thread does not raise and simply does nothing.
As an optional way to reduce duplication, introduce a shared base class named AbstractSmartLock in locklib/locks/smart_lock/abstract.py. Move the current SmartLock logic there, make the recursive-acquire behavior conditional on a class-level recursive flag, and make SmartLock and SmartRLock inherit from it with bodies containing only recursive = False and recursive = True, respectively.
Context
- locklib: 0.0.23
- Python: 3.8.10
- OS: macOS / Darwin 24.3.0
SmartLockdeadlocks when the same thread tries to acquire the same lock twice. The deadlock is not reported as an exception, so code usingSmartLockfor deadlock detection can still hang on this self-recursive case.Reproduction
Current output:
Expected behavior
The second acquire should not block forever.
SmartLockshould report this deadlock case instead of leaving the thread stuck.Actual behavior
The second acquire never returns, and no exception is raised.
Proposed solution
Reproduce the semantics of standard Python locks by replacing the current single
SmartLockclass with two classes:SmartLock: raises an exception when the same thread tries to acquire the same lock recursively. This behavior needs to be added.SmartRLock: behaves likeSmartLockin every other respect, but differs in this case: recursive acquire by the same thread does not raise and simply does nothing.As an optional way to reduce duplication, introduce a shared base class named
AbstractSmartLockinlocklib/locks/smart_lock/abstract.py. Move the currentSmartLocklogic there, make the recursive-acquire behavior conditional on a class-levelrecursiveflag, and makeSmartLockandSmartRLockinherit from it with bodies containing onlyrecursive = Falseandrecursive = True, respectively.Context