Message9834
The documentation for `threading.Lock` says (emphasis added):
A factory function that returns a new primitive lock object. Once a thread has acquired it, subsequent attempts to acquire it block, until it is released; *any thread may release it*.
This is in contrast with `threading.RLock` which specifically says that a "reentrant lock must be released by the thread that acquired it."
Jython uses the same implementation for both types of locks (Lock.java), and it obeys the semantics of `RLock` by requiring that the releasing thread be the acquiring thread, raising an exception if that's not the case. This can cause problems for applications that make advanced use of locks.
Consider this example in Jython:
$ ../jython/dist/bin/jython
Jython 2.7rc2+ (default:5064a5c5b1a3, Apr 14 2015, 06:28:43)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_40
Type "help", "copyright", "credits" or "license" for more information.
>>> import threading
>>> threading.Lock is threading.RLock
True
>>> lock = threading.Lock()
>>> lock.acquire()
True
>>> t = threading.Thread(target=lock.release)
>>> t.start(); t.join()
>>> Exception in thread Thread-1:Traceback (most recent call last):
File "//jython/dist/Lib/threading.py", line 222, in _Thread__bootstrap
self.run()
File "//jython/dist/Lib/threading.py", line 213, in run
self._target(*self._args, **self._kwargs)
RuntimeError: cannot release un-acquired lock
>>> lock.locked()
True
Compare to the CPython and PyPy behaviour:
$ /opt/local/bin/python2.7
Python 2.7.9 (default, Dec 13 2014, 15:13:49)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import threading
>>> threading.Lock is threading.RLock
False
>>> lock = threading.Lock()
>>> lock.acquire()
True
>>> t = threading.Thread(target=lock.release)
>>> t.start(); t.join()
>>> lock.locked()
False
One real-world example of this is ZODB, at least its test suite. Exceptions like the following are fairly common (fortunately releasing the lock is the last thing the thread was going to do, and then the lock gets destroyed anyway so it's not an immediate issue in this case---the failure has no consequences for the test):
Exception in thread commit:Traceback (most recent call last):
File "//jython/dist/Lib/threading.py", line 222, in _Thread__bootstrap
self.run()
File "//jython/dist/Lib/threading.py", line 213, in run
self._target(*self._args, **self._kwargs)
File "//ZODB/src/ZODB/tests/BasicStorage.py", line 343, in commit
self._storage.tpc_finish(t, callback)
File "//ZODB/src/ZODB/utils.py", line 293, in __call__
return func(*args, **kw)
File "//ZODB/src/ZODB/DemoStorage.py", line 349, in tpc_finish
self.changes.tpc_finish(transaction, func)
File "//ZODB/src/ZODB/utils.py", line 293, in __call__
return func(*args, **kw)
File "//ZODB/src/ZODB/MappingStorage.py", line 318, in tpc_finish
self._commit_lock.release()
RuntimeError: cannot release un-acquired lock |
|
Date |
User |
Action |
Args |
2015-04-14 12:37:10 | jmadden | set | recipients:
+ jmadden |
2015-04-14 12:37:10 | jmadden | set | messageid: <1429015030.94.0.347815765349.issue2328@psf.upfronthosting.co.za> |
2015-04-14 12:37:10 | jmadden | link | issue2328 messages |
2015-04-14 12:37:10 | jmadden | create | |
|