Closes #17375: port new threading docstrings from 2.7.
This commit is contained in:
parent
5d5b375c84
commit
c30b59fe3d
406
Lib/threading.py
406
Lib/threading.py
|
@ -44,10 +44,22 @@ _profile_hook = None
|
||||||
_trace_hook = None
|
_trace_hook = None
|
||||||
|
|
||||||
def setprofile(func):
|
def setprofile(func):
|
||||||
|
"""Set a profile function for all threads started from the threading module.
|
||||||
|
|
||||||
|
The func will be passed to sys.setprofile() for each thread, before its
|
||||||
|
run() method is called.
|
||||||
|
|
||||||
|
"""
|
||||||
global _profile_hook
|
global _profile_hook
|
||||||
_profile_hook = func
|
_profile_hook = func
|
||||||
|
|
||||||
def settrace(func):
|
def settrace(func):
|
||||||
|
"""Set a trace function for all threads started from the threading module.
|
||||||
|
|
||||||
|
The func will be passed to sys.settrace() for each thread, before its run()
|
||||||
|
method is called.
|
||||||
|
|
||||||
|
"""
|
||||||
global _trace_hook
|
global _trace_hook
|
||||||
_trace_hook = func
|
_trace_hook = func
|
||||||
|
|
||||||
|
@ -56,11 +68,27 @@ def settrace(func):
|
||||||
Lock = _allocate_lock
|
Lock = _allocate_lock
|
||||||
|
|
||||||
def RLock(*args, **kwargs):
|
def RLock(*args, **kwargs):
|
||||||
|
"""Factory function that returns a new reentrant lock.
|
||||||
|
|
||||||
|
A reentrant lock must be released by the thread that acquired it. Once a
|
||||||
|
thread has acquired a reentrant lock, the same thread may acquire it again
|
||||||
|
without blocking; the thread must release it once for each time it has
|
||||||
|
acquired it.
|
||||||
|
|
||||||
|
"""
|
||||||
if _CRLock is None:
|
if _CRLock is None:
|
||||||
return _PyRLock(*args, **kwargs)
|
return _PyRLock(*args, **kwargs)
|
||||||
return _CRLock(*args, **kwargs)
|
return _CRLock(*args, **kwargs)
|
||||||
|
|
||||||
class _RLock:
|
class _RLock:
|
||||||
|
"""This class implements reentrant lock objects.
|
||||||
|
|
||||||
|
A reentrant lock must be released by the thread that acquired it. Once a
|
||||||
|
thread has acquired a reentrant lock, the same thread may acquire it
|
||||||
|
again without blocking; the thread must release it once for each time it
|
||||||
|
has acquired it.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._block = _allocate_lock()
|
self._block = _allocate_lock()
|
||||||
|
@ -77,6 +105,31 @@ class _RLock:
|
||||||
self.__class__.__name__, owner, self._count)
|
self.__class__.__name__, owner, self._count)
|
||||||
|
|
||||||
def acquire(self, blocking=True, timeout=-1):
|
def acquire(self, blocking=True, timeout=-1):
|
||||||
|
"""Acquire a lock, blocking or non-blocking.
|
||||||
|
|
||||||
|
When invoked without arguments: if this thread already owns the lock,
|
||||||
|
increment the recursion level by one, and return immediately. Otherwise,
|
||||||
|
if another thread owns the lock, block until the lock is unlocked. Once
|
||||||
|
the lock is unlocked (not owned by any thread), then grab ownership, set
|
||||||
|
the recursion level to one, and return. If more than one thread is
|
||||||
|
blocked waiting until the lock is unlocked, only one at a time will be
|
||||||
|
able to grab ownership of the lock. There is no return value in this
|
||||||
|
case.
|
||||||
|
|
||||||
|
When invoked with the blocking argument set to true, do the same thing
|
||||||
|
as when called without arguments, and return true.
|
||||||
|
|
||||||
|
When invoked with the blocking argument set to false, do not block. If a
|
||||||
|
call without an argument would block, return false immediately;
|
||||||
|
otherwise, do the same thing as when called without arguments, and
|
||||||
|
return true.
|
||||||
|
|
||||||
|
When invoked with the floating-point timeout argument set to a positive
|
||||||
|
value, block for at most the number of seconds specified by timeout
|
||||||
|
and as long as the lock cannot be acquired. Return true if the lock has
|
||||||
|
been acquired, false if the timeout has elapsed.
|
||||||
|
|
||||||
|
"""
|
||||||
me = get_ident()
|
me = get_ident()
|
||||||
if self._owner == me:
|
if self._owner == me:
|
||||||
self._count = self._count + 1
|
self._count = self._count + 1
|
||||||
|
@ -90,6 +143,21 @@ class _RLock:
|
||||||
__enter__ = acquire
|
__enter__ = acquire
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
|
"""Release a lock, decrementing the recursion level.
|
||||||
|
|
||||||
|
If after the decrement it is zero, reset the lock to unlocked (not owned
|
||||||
|
by any thread), and if any other threads are blocked waiting for the
|
||||||
|
lock to become unlocked, allow exactly one of them to proceed. If after
|
||||||
|
the decrement the recursion level is still nonzero, the lock remains
|
||||||
|
locked and owned by the calling thread.
|
||||||
|
|
||||||
|
Only call this method when the calling thread owns the lock. A
|
||||||
|
RuntimeError is raised if this method is called when the lock is
|
||||||
|
unlocked.
|
||||||
|
|
||||||
|
There is no return value.
|
||||||
|
|
||||||
|
"""
|
||||||
if self._owner != get_ident():
|
if self._owner != get_ident():
|
||||||
raise RuntimeError("cannot release un-acquired lock")
|
raise RuntimeError("cannot release un-acquired lock")
|
||||||
self._count = count = self._count - 1
|
self._count = count = self._count - 1
|
||||||
|
@ -123,6 +191,16 @@ _PyRLock = _RLock
|
||||||
|
|
||||||
|
|
||||||
class Condition:
|
class Condition:
|
||||||
|
"""Class that implements a condition variable.
|
||||||
|
|
||||||
|
A condition variable allows one or more threads to wait until they are
|
||||||
|
notified by another thread.
|
||||||
|
|
||||||
|
If the lock argument is given and not None, it must be a Lock or RLock
|
||||||
|
object, and it is used as the underlying lock. Otherwise, a new RLock object
|
||||||
|
is created and used as the underlying lock.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, lock=None):
|
def __init__(self, lock=None):
|
||||||
if lock is None:
|
if lock is None:
|
||||||
|
@ -173,6 +251,28 @@ class Condition:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
|
"""Wait until notified or until a timeout occurs.
|
||||||
|
|
||||||
|
If the calling thread has not acquired the lock when this method is
|
||||||
|
called, a RuntimeError is raised.
|
||||||
|
|
||||||
|
This method releases the underlying lock, and then blocks until it is
|
||||||
|
awakened by a notify() or notify_all() call for the same condition
|
||||||
|
variable in another thread, or until the optional timeout occurs. Once
|
||||||
|
awakened or timed out, it re-acquires the lock and returns.
|
||||||
|
|
||||||
|
When the timeout argument is present and not None, it should be a
|
||||||
|
floating point number specifying a timeout for the operation in seconds
|
||||||
|
(or fractions thereof).
|
||||||
|
|
||||||
|
When the underlying lock is an RLock, it is not released using its
|
||||||
|
release() method, since this may not actually unlock the lock when it
|
||||||
|
was acquired multiple times recursively. Instead, an internal interface
|
||||||
|
of the RLock class is used, which really unlocks it even when it has
|
||||||
|
been recursively acquired several times. Another internal interface is
|
||||||
|
then used to restore the recursion level when the lock is reacquired.
|
||||||
|
|
||||||
|
"""
|
||||||
if not self._is_owned():
|
if not self._is_owned():
|
||||||
raise RuntimeError("cannot wait on un-acquired lock")
|
raise RuntimeError("cannot wait on un-acquired lock")
|
||||||
waiter = _allocate_lock()
|
waiter = _allocate_lock()
|
||||||
|
@ -198,6 +298,13 @@ class Condition:
|
||||||
self._acquire_restore(saved_state)
|
self._acquire_restore(saved_state)
|
||||||
|
|
||||||
def wait_for(self, predicate, timeout=None):
|
def wait_for(self, predicate, timeout=None):
|
||||||
|
"""Wait until a condition evaluates to True.
|
||||||
|
|
||||||
|
predicate should be a callable which result will be interpreted as a
|
||||||
|
boolean value. A timeout may be provided giving the maximum time to
|
||||||
|
wait.
|
||||||
|
|
||||||
|
"""
|
||||||
endtime = None
|
endtime = None
|
||||||
waittime = timeout
|
waittime = timeout
|
||||||
result = predicate()
|
result = predicate()
|
||||||
|
@ -214,6 +321,15 @@ class Condition:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def notify(self, n=1):
|
def notify(self, n=1):
|
||||||
|
"""Wake up one or more threads waiting on this condition, if any.
|
||||||
|
|
||||||
|
If the calling thread has not acquired the lock when this method is
|
||||||
|
called, a RuntimeError is raised.
|
||||||
|
|
||||||
|
This method wakes up at most n of the threads waiting for the condition
|
||||||
|
variable; it is a no-op if no threads are waiting.
|
||||||
|
|
||||||
|
"""
|
||||||
if not self._is_owned():
|
if not self._is_owned():
|
||||||
raise RuntimeError("cannot notify on un-acquired lock")
|
raise RuntimeError("cannot notify on un-acquired lock")
|
||||||
__waiters = self._waiters
|
__waiters = self._waiters
|
||||||
|
@ -228,12 +344,26 @@ class Condition:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def notify_all(self):
|
def notify_all(self):
|
||||||
|
"""Wake up all threads waiting on this condition.
|
||||||
|
|
||||||
|
If the calling thread has not acquired the lock when this method
|
||||||
|
is called, a RuntimeError is raised.
|
||||||
|
|
||||||
|
"""
|
||||||
self.notify(len(self._waiters))
|
self.notify(len(self._waiters))
|
||||||
|
|
||||||
notifyAll = notify_all
|
notifyAll = notify_all
|
||||||
|
|
||||||
|
|
||||||
class Semaphore:
|
class Semaphore:
|
||||||
|
"""This class implements semaphore objects.
|
||||||
|
|
||||||
|
Semaphores manage a counter representing the number of release() calls minus
|
||||||
|
the number of acquire() calls, plus an initial value. The acquire() method
|
||||||
|
blocks if necessary until it can return without making the counter
|
||||||
|
negative. If not given, value defaults to 1.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
# After Tim Peters' semaphore class, but not quite the same (no maximum)
|
# After Tim Peters' semaphore class, but not quite the same (no maximum)
|
||||||
|
|
||||||
|
@ -244,6 +374,29 @@ class Semaphore:
|
||||||
self._value = value
|
self._value = value
|
||||||
|
|
||||||
def acquire(self, blocking=True, timeout=None):
|
def acquire(self, blocking=True, timeout=None):
|
||||||
|
"""Acquire a semaphore, decrementing the internal counter by one.
|
||||||
|
|
||||||
|
When invoked without arguments: if the internal counter is larger than
|
||||||
|
zero on entry, decrement it by one and return immediately. If it is zero
|
||||||
|
on entry, block, waiting until some other thread has called release() to
|
||||||
|
make it larger than zero. This is done with proper interlocking so that
|
||||||
|
if multiple acquire() calls are blocked, release() will wake exactly one
|
||||||
|
of them up. The implementation may pick one at random, so the order in
|
||||||
|
which blocked threads are awakened should not be relied on. There is no
|
||||||
|
return value in this case.
|
||||||
|
|
||||||
|
When invoked with blocking set to true, do the same thing as when called
|
||||||
|
without arguments, and return true.
|
||||||
|
|
||||||
|
When invoked with blocking set to false, do not block. If a call without
|
||||||
|
an argument would block, return false immediately; otherwise, do the
|
||||||
|
same thing as when called without arguments, and return true.
|
||||||
|
|
||||||
|
When invoked with a timeout other than None, it will block for at
|
||||||
|
most timeout seconds. If acquire does not complete successfully in
|
||||||
|
that interval, return false. Return true otherwise.
|
||||||
|
|
||||||
|
"""
|
||||||
if not blocking and timeout is not None:
|
if not blocking and timeout is not None:
|
||||||
raise ValueError("can't specify timeout for non-blocking acquire")
|
raise ValueError("can't specify timeout for non-blocking acquire")
|
||||||
rc = False
|
rc = False
|
||||||
|
@ -268,6 +421,12 @@ class Semaphore:
|
||||||
__enter__ = acquire
|
__enter__ = acquire
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
|
"""Release a semaphore, incrementing the internal counter by one.
|
||||||
|
|
||||||
|
When the counter is zero on entry and another thread is waiting for it
|
||||||
|
to become larger than zero again, wake up that thread.
|
||||||
|
|
||||||
|
"""
|
||||||
with self._cond:
|
with self._cond:
|
||||||
self._value = self._value + 1
|
self._value = self._value + 1
|
||||||
self._cond.notify()
|
self._cond.notify()
|
||||||
|
@ -277,12 +436,36 @@ class Semaphore:
|
||||||
|
|
||||||
|
|
||||||
class BoundedSemaphore(Semaphore):
|
class BoundedSemaphore(Semaphore):
|
||||||
"""Semaphore that checks that # releases is <= # acquires"""
|
"""Implements a bounded semaphore.
|
||||||
|
|
||||||
|
A bounded semaphore checks to make sure its current value doesn't exceed its
|
||||||
|
initial value. If it does, ValueError is raised. In most situations
|
||||||
|
semaphores are used to guard resources with limited capacity.
|
||||||
|
|
||||||
|
If the semaphore is released too many times it's a sign of a bug. If not
|
||||||
|
given, value defaults to 1.
|
||||||
|
|
||||||
|
Like regular semaphores, bounded semaphores manage a counter representing
|
||||||
|
the number of release() calls minus the number of acquire() calls, plus an
|
||||||
|
initial value. The acquire() method blocks if necessary until it can return
|
||||||
|
without making the counter negative. If not given, value defaults to 1.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, value=1):
|
def __init__(self, value=1):
|
||||||
Semaphore.__init__(self, value)
|
Semaphore.__init__(self, value)
|
||||||
self._initial_value = value
|
self._initial_value = value
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
|
"""Release a semaphore, incrementing the internal counter by one.
|
||||||
|
|
||||||
|
When the counter is zero on entry and another thread is waiting for it
|
||||||
|
to become larger than zero again, wake up that thread.
|
||||||
|
|
||||||
|
If the number of releases exceeds the number of acquires,
|
||||||
|
raise a ValueError.
|
||||||
|
|
||||||
|
"""
|
||||||
with self._cond:
|
with self._cond:
|
||||||
if self._value >= self._initial_value:
|
if self._value >= self._initial_value:
|
||||||
raise ValueError("Semaphore released too many times")
|
raise ValueError("Semaphore released too many times")
|
||||||
|
@ -291,6 +474,13 @@ class BoundedSemaphore(Semaphore):
|
||||||
|
|
||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
|
"""Class implementing event objects.
|
||||||
|
|
||||||
|
Events manage a flag that can be set to true with the set() method and reset
|
||||||
|
to false with the clear() method. The wait() method blocks until the flag is
|
||||||
|
true. The flag is initially false.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
# After Tim Peters' event class (without is_posted())
|
# After Tim Peters' event class (without is_posted())
|
||||||
|
|
||||||
|
@ -303,11 +493,18 @@ class Event:
|
||||||
self._cond.__init__()
|
self._cond.__init__()
|
||||||
|
|
||||||
def is_set(self):
|
def is_set(self):
|
||||||
|
"""Return true if and only if the internal flag is true."""
|
||||||
return self._flag
|
return self._flag
|
||||||
|
|
||||||
isSet = is_set
|
isSet = is_set
|
||||||
|
|
||||||
def set(self):
|
def set(self):
|
||||||
|
"""Set the internal flag to true.
|
||||||
|
|
||||||
|
All threads waiting for it to become true are awakened. Threads
|
||||||
|
that call wait() once the flag is true will not block at all.
|
||||||
|
|
||||||
|
"""
|
||||||
self._cond.acquire()
|
self._cond.acquire()
|
||||||
try:
|
try:
|
||||||
self._flag = True
|
self._flag = True
|
||||||
|
@ -316,6 +513,12 @@ class Event:
|
||||||
self._cond.release()
|
self._cond.release()
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
"""Reset the internal flag to false.
|
||||||
|
|
||||||
|
Subsequently, threads calling wait() will block until set() is called to
|
||||||
|
set the internal flag to true again.
|
||||||
|
|
||||||
|
"""
|
||||||
self._cond.acquire()
|
self._cond.acquire()
|
||||||
try:
|
try:
|
||||||
self._flag = False
|
self._flag = False
|
||||||
|
@ -323,6 +526,20 @@ class Event:
|
||||||
self._cond.release()
|
self._cond.release()
|
||||||
|
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
|
"""Block until the internal flag is true.
|
||||||
|
|
||||||
|
If the internal flag is true on entry, return immediately. Otherwise,
|
||||||
|
block until another thread calls set() to set the flag to true, or until
|
||||||
|
the optional timeout occurs.
|
||||||
|
|
||||||
|
When the timeout argument is present and not None, it should be a
|
||||||
|
floating point number specifying a timeout for the operation in seconds
|
||||||
|
(or fractions thereof).
|
||||||
|
|
||||||
|
This method returns the internal flag on exit, so it will always return
|
||||||
|
True except if a timeout is given and the operation times out.
|
||||||
|
|
||||||
|
"""
|
||||||
self._cond.acquire()
|
self._cond.acquire()
|
||||||
try:
|
try:
|
||||||
signaled = self._flag
|
signaled = self._flag
|
||||||
|
@ -345,19 +562,22 @@ class Event:
|
||||||
# similar to 'draining' except that threads leave with a BrokenBarrierError,
|
# similar to 'draining' except that threads leave with a BrokenBarrierError,
|
||||||
# and a 'broken' state in which all threads get the exception.
|
# and a 'broken' state in which all threads get the exception.
|
||||||
class Barrier:
|
class Barrier:
|
||||||
|
"""Implements a Barrier.
|
||||||
|
|
||||||
|
Useful for synchronizing a fixed number of threads at known synchronization
|
||||||
|
points. Threads block on 'wait()' and are simultaneously once they have all
|
||||||
|
made that call.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Barrier. Useful for synchronizing a fixed number of threads
|
|
||||||
at known synchronization points. Threads block on 'wait()' and are
|
|
||||||
simultaneously once they have all made that call.
|
|
||||||
"""
|
|
||||||
def __init__(self, parties, action=None, timeout=None):
|
def __init__(self, parties, action=None, timeout=None):
|
||||||
"""
|
"""Create a barrier, initialised to 'parties' threads.
|
||||||
Create a barrier, initialised to 'parties' threads.
|
|
||||||
'action' is a callable which, when supplied, will be called
|
'action' is a callable which, when supplied, will be called by one of
|
||||||
by one of the threads after they have all entered the
|
the threads after they have all entered the barrier and just prior to
|
||||||
barrier and just prior to releasing them all.
|
releasing them all. If a 'timeout' is provided, it is uses as the
|
||||||
If a 'timeout' is provided, it is uses as the default for
|
default for all subsequent 'wait()' calls.
|
||||||
all subsequent 'wait()' calls.
|
|
||||||
"""
|
"""
|
||||||
self._cond = Condition(Lock())
|
self._cond = Condition(Lock())
|
||||||
self._action = action
|
self._action = action
|
||||||
|
@ -367,12 +587,13 @@ class Barrier:
|
||||||
self._count = 0
|
self._count = 0
|
||||||
|
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
"""
|
"""Wait for the barrier.
|
||||||
Wait for the barrier. When the specified number of threads have
|
|
||||||
started waiting, they are all simultaneously awoken. If an 'action'
|
When the specified number of threads have started waiting, they are all
|
||||||
was provided for the barrier, one of the threads will have executed
|
simultaneously awoken. If an 'action' was provided for the barrier, one
|
||||||
that callback prior to returning.
|
of the threads will have executed that callback prior to returning.
|
||||||
Returns an individual index number from 0 to 'parties-1'.
|
Returns an individual index number from 0 to 'parties-1'.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if timeout is None:
|
if timeout is None:
|
||||||
timeout = self._timeout
|
timeout = self._timeout
|
||||||
|
@ -439,10 +660,11 @@ class Barrier:
|
||||||
self._cond.notify_all()
|
self._cond.notify_all()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""
|
"""Reset the barrier to the initial state.
|
||||||
Reset the barrier to the initial state.
|
|
||||||
Any threads currently waiting will get the BrokenBarrier exception
|
Any threads currently waiting will get the BrokenBarrier exception
|
||||||
raised.
|
raised.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with self._cond:
|
with self._cond:
|
||||||
if self._count > 0:
|
if self._count > 0:
|
||||||
|
@ -458,11 +680,11 @@ class Barrier:
|
||||||
self._cond.notify_all()
|
self._cond.notify_all()
|
||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
"""
|
"""Place the barrier into a 'broken' state.
|
||||||
Place the barrier into a 'broken' state.
|
|
||||||
Useful in case of error. Any currently waiting threads and
|
Useful in case of error. Any currently waiting threads and threads
|
||||||
threads attempting to 'wait()' will have BrokenBarrierError
|
attempting to 'wait()' will have BrokenBarrierError raised.
|
||||||
raised.
|
|
||||||
"""
|
"""
|
||||||
with self._cond:
|
with self._cond:
|
||||||
self._break()
|
self._break()
|
||||||
|
@ -475,16 +697,12 @@ class Barrier:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parties(self):
|
def parties(self):
|
||||||
"""
|
"""Return the number of threads required to trip the barrier."""
|
||||||
Return the number of threads required to trip the barrier.
|
|
||||||
"""
|
|
||||||
return self._parties
|
return self._parties
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def n_waiting(self):
|
def n_waiting(self):
|
||||||
"""
|
"""Return the number of threads currently waiting at the barrier."""
|
||||||
Return the number of threads that are currently waiting at the barrier.
|
|
||||||
"""
|
|
||||||
# We don't need synchronization here since this is an ephemeral result
|
# We don't need synchronization here since this is an ephemeral result
|
||||||
# anyway. It returns the correct value in the steady state.
|
# anyway. It returns the correct value in the steady state.
|
||||||
if self._state == 0:
|
if self._state == 0:
|
||||||
|
@ -493,13 +711,12 @@ class Barrier:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def broken(self):
|
def broken(self):
|
||||||
"""
|
"""Return True if the barrier is in a broken state."""
|
||||||
Return True if the barrier is in a broken state
|
|
||||||
"""
|
|
||||||
return self._state == -2
|
return self._state == -2
|
||||||
|
|
||||||
# exception raised by the Barrier class
|
# exception raised by the Barrier class
|
||||||
class BrokenBarrierError(RuntimeError): pass
|
class BrokenBarrierError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Helper to generate new thread names
|
# Helper to generate new thread names
|
||||||
|
@ -520,6 +737,13 @@ _dangling = WeakSet()
|
||||||
# Main class for threads
|
# Main class for threads
|
||||||
|
|
||||||
class Thread:
|
class Thread:
|
||||||
|
"""A class that represents a thread of control.
|
||||||
|
|
||||||
|
This class can be safely subclassed in a limited fashion. There are two ways
|
||||||
|
to specify the activity: by passing a callable object to the constructor, or
|
||||||
|
by overriding the run() method in a subclass.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
__initialized = False
|
__initialized = False
|
||||||
# Need to store a reference to sys.exc_info for printing
|
# Need to store a reference to sys.exc_info for printing
|
||||||
|
@ -533,6 +757,27 @@ class Thread:
|
||||||
|
|
||||||
def __init__(self, group=None, target=None, name=None,
|
def __init__(self, group=None, target=None, name=None,
|
||||||
args=(), kwargs=None, *, daemon=None):
|
args=(), kwargs=None, *, daemon=None):
|
||||||
|
"""This constructor should always be called with keyword arguments. Arguments are:
|
||||||
|
|
||||||
|
*group* should be None; reserved for future extension when a ThreadGroup
|
||||||
|
class is implemented.
|
||||||
|
|
||||||
|
*target* is the callable object to be invoked by the run()
|
||||||
|
method. Defaults to None, meaning nothing is called.
|
||||||
|
|
||||||
|
*name* is the thread name. By default, a unique name is constructed of
|
||||||
|
the form "Thread-N" where N is a small decimal number.
|
||||||
|
|
||||||
|
*args* is the argument tuple for the target invocation. Defaults to ().
|
||||||
|
|
||||||
|
*kwargs* is a dictionary of keyword arguments for the target
|
||||||
|
invocation. Defaults to {}.
|
||||||
|
|
||||||
|
If a subclass overrides the constructor, it must make sure to invoke
|
||||||
|
the base class constructor (Thread.__init__()) before doing anything
|
||||||
|
else to the thread.
|
||||||
|
|
||||||
|
"""
|
||||||
assert group is None, "group argument must be None for now"
|
assert group is None, "group argument must be None for now"
|
||||||
if kwargs is None:
|
if kwargs is None:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
@ -575,6 +820,15 @@ class Thread:
|
||||||
return "<%s(%s, %s)>" % (self.__class__.__name__, self._name, status)
|
return "<%s(%s, %s)>" % (self.__class__.__name__, self._name, status)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
"""Start the thread's activity.
|
||||||
|
|
||||||
|
It must be called at most once per thread object. It arranges for the
|
||||||
|
object's run() method to be invoked in a separate thread of control.
|
||||||
|
|
||||||
|
This method will raise a RuntimeError if called more than once on the
|
||||||
|
same thread object.
|
||||||
|
|
||||||
|
"""
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
raise RuntimeError("thread.__init__() not called")
|
raise RuntimeError("thread.__init__() not called")
|
||||||
|
|
||||||
|
@ -591,6 +845,14 @@ class Thread:
|
||||||
self._started.wait()
|
self._started.wait()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
"""Method representing the thread's activity.
|
||||||
|
|
||||||
|
You may override this method in a subclass. The standard run() method
|
||||||
|
invokes the callable object passed to the object's constructor as the
|
||||||
|
target argument, if any, with sequential and keyword arguments taken
|
||||||
|
from the args and kwargs arguments, respectively.
|
||||||
|
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if self._target:
|
if self._target:
|
||||||
self._target(*self._args, **self._kwargs)
|
self._target(*self._args, **self._kwargs)
|
||||||
|
@ -729,6 +991,29 @@ class Thread:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def join(self, timeout=None):
|
def join(self, timeout=None):
|
||||||
|
"""Wait until the thread terminates.
|
||||||
|
|
||||||
|
This blocks the calling thread until the thread whose join() method is
|
||||||
|
called terminates -- either normally or through an unhandled exception
|
||||||
|
or until the optional timeout occurs.
|
||||||
|
|
||||||
|
When the timeout argument is present and not None, it should be a
|
||||||
|
floating point number specifying a timeout for the operation in seconds
|
||||||
|
(or fractions thereof). As join() always returns None, you must call
|
||||||
|
isAlive() after join() to decide whether a timeout happened -- if the
|
||||||
|
thread is still alive, the join() call timed out.
|
||||||
|
|
||||||
|
When the timeout argument is not present or None, the operation will
|
||||||
|
block until the thread terminates.
|
||||||
|
|
||||||
|
A thread can be join()ed many times.
|
||||||
|
|
||||||
|
join() raises a RuntimeError if an attempt is made to join the current
|
||||||
|
thread as that would cause a deadlock. It is also an error to join() a
|
||||||
|
thread before it has been started and attempts to do so raises the same
|
||||||
|
exception.
|
||||||
|
|
||||||
|
"""
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
raise RuntimeError("Thread.__init__() not called")
|
raise RuntimeError("Thread.__init__() not called")
|
||||||
if not self._started.is_set():
|
if not self._started.is_set():
|
||||||
|
@ -753,6 +1038,12 @@ class Thread:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
"""A string used for identification purposes only.
|
||||||
|
|
||||||
|
It has no semantics. Multiple threads may be given the same name. The
|
||||||
|
initial name is set by the constructor.
|
||||||
|
|
||||||
|
"""
|
||||||
assert self._initialized, "Thread.__init__() not called"
|
assert self._initialized, "Thread.__init__() not called"
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
@ -763,10 +1054,24 @@ class Thread:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ident(self):
|
def ident(self):
|
||||||
|
"""Thread identifier of this thread or None if it has not been started.
|
||||||
|
|
||||||
|
This is a nonzero integer. See the thread.get_ident() function. Thread
|
||||||
|
identifiers may be recycled when a thread exits and another thread is
|
||||||
|
created. The identifier is available even after the thread has exited.
|
||||||
|
|
||||||
|
"""
|
||||||
assert self._initialized, "Thread.__init__() not called"
|
assert self._initialized, "Thread.__init__() not called"
|
||||||
return self._ident
|
return self._ident
|
||||||
|
|
||||||
def is_alive(self):
|
def is_alive(self):
|
||||||
|
"""Return whether the thread is alive.
|
||||||
|
|
||||||
|
This method returns True just before the run() method starts until just
|
||||||
|
after the run() method terminates. The module function enumerate()
|
||||||
|
returns a list of all alive threads.
|
||||||
|
|
||||||
|
"""
|
||||||
assert self._initialized, "Thread.__init__() not called"
|
assert self._initialized, "Thread.__init__() not called"
|
||||||
return self._started.is_set() and not self._stopped
|
return self._started.is_set() and not self._stopped
|
||||||
|
|
||||||
|
@ -774,6 +1079,17 @@ class Thread:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def daemon(self):
|
def daemon(self):
|
||||||
|
"""A boolean value indicating whether this thread is a daemon thread.
|
||||||
|
|
||||||
|
This must be set before start() is called, otherwise RuntimeError is
|
||||||
|
raised. Its initial value is inherited from the creating thread; the
|
||||||
|
main thread is not a daemon thread and therefore all threads created in
|
||||||
|
the main thread default to daemon = False.
|
||||||
|
|
||||||
|
The entire Python program exits when no alive non-daemon threads are
|
||||||
|
left.
|
||||||
|
|
||||||
|
"""
|
||||||
assert self._initialized, "Thread.__init__() not called"
|
assert self._initialized, "Thread.__init__() not called"
|
||||||
return self._daemonic
|
return self._daemonic
|
||||||
|
|
||||||
|
@ -805,6 +1121,7 @@ class Timer(Thread):
|
||||||
t = Timer(30.0, f, args=None, kwargs=None)
|
t = Timer(30.0, f, args=None, kwargs=None)
|
||||||
t.start()
|
t.start()
|
||||||
t.cancel() # stop the timer's action if it's still waiting
|
t.cancel() # stop the timer's action if it's still waiting
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, interval, function, args=None, kwargs=None):
|
def __init__(self, interval, function, args=None, kwargs=None):
|
||||||
|
@ -816,7 +1133,7 @@ class Timer(Thread):
|
||||||
self.finished = Event()
|
self.finished = Event()
|
||||||
|
|
||||||
def cancel(self):
|
def cancel(self):
|
||||||
"""Stop the timer if it hasn't finished yet"""
|
"""Stop the timer if it hasn't finished yet."""
|
||||||
self.finished.set()
|
self.finished.set()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -885,6 +1202,12 @@ class _DummyThread(Thread):
|
||||||
# Global API functions
|
# Global API functions
|
||||||
|
|
||||||
def current_thread():
|
def current_thread():
|
||||||
|
"""Return the current Thread object, corresponding to the caller's thread of control.
|
||||||
|
|
||||||
|
If the caller's thread of control was not created through the threading
|
||||||
|
module, a dummy thread object with limited functionality is returned.
|
||||||
|
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return _active[get_ident()]
|
return _active[get_ident()]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -893,6 +1216,12 @@ def current_thread():
|
||||||
currentThread = current_thread
|
currentThread = current_thread
|
||||||
|
|
||||||
def active_count():
|
def active_count():
|
||||||
|
"""Return the number of Thread objects currently alive.
|
||||||
|
|
||||||
|
The returned count is equal to the length of the list returned by
|
||||||
|
enumerate().
|
||||||
|
|
||||||
|
"""
|
||||||
with _active_limbo_lock:
|
with _active_limbo_lock:
|
||||||
return len(_active) + len(_limbo)
|
return len(_active) + len(_limbo)
|
||||||
|
|
||||||
|
@ -903,6 +1232,13 @@ def _enumerate():
|
||||||
return list(_active.values()) + list(_limbo.values())
|
return list(_active.values()) + list(_limbo.values())
|
||||||
|
|
||||||
def enumerate():
|
def enumerate():
|
||||||
|
"""Return a list of all Thread objects currently alive.
|
||||||
|
|
||||||
|
The list includes daemonic threads, dummy thread objects created by
|
||||||
|
current_thread(), and the main thread. It excludes terminated threads and
|
||||||
|
threads that have not yet been started.
|
||||||
|
|
||||||
|
"""
|
||||||
with _active_limbo_lock:
|
with _active_limbo_lock:
|
||||||
return list(_active.values()) + list(_limbo.values())
|
return list(_active.values()) + list(_limbo.values())
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue