Semaphore
is implemented in pure Python - see http://hg.python.org/cpython/file/3.3/Lib/threading.py , starting at line 236. The acquire
method is implemented this way:
def acquire(self, blocking=True, timeout=None):
if not blocking and timeout is not None:
raise ValueError("can't specify timeout for non-blocking acquire")
rc = False
endtime = None
with self._cond:
while self._value == 0:
if not blocking:
break
if timeout is not None:
if endtime is None:
endtime = _time() + timeout
else:
timeout = endtime - _time()
if timeout <= 0:
break
self._cond.wait(timeout)
else:
self._value = self._value - 1
rc = True
return rc
self._cond
is a Condition wrapping a Lock.
You could use Semaphore
's technique directly in your code instead of using the class, but it would probably be easier to copy the entire class into your own code. If forward compatibility is an issue, you could even condition it out like so:
from threading import *
from sys import version_info
if version_info < (3, 2):
# Need timeout in Semaphore.acquire,
# from Python 3.3 threading.py
class Semaphore:
...
Whichever way you do this, you will also need the new Condition
class - according to the docs for Condition.wait
,
The return value is True
unless a given timeout expired, in which case
it is False
.
Changed in version 3.2: Previously, the method always returned None
.
The Semaphore
timeout code relies on this behavior. The rabbit hole doesn't appear to go any deeper than that, but, your easiest solution might even be to copy the entire 3.3 threading.py
, make any changes it needs to run on 2.x, and add a prominent comment at the top that you're deliberately shadowing the stdlib.