diff options
author | Tim Peters <tim@python.org> | 2013-09-09 17:57:10 (GMT) |
---|---|---|
committer | Tim Peters <tim@python.org> | 2013-09-09 17:57:10 (GMT) |
commit | 7a6054b19dae9c65ce7cfe897ac589448972b646 (patch) | |
tree | 012f8d89e1d5a76ed1e0512d18c387b3a64b06eb /Lib/threading.py | |
parent | 8568f66daf088cf235a42288621fb4770ac48199 (diff) | |
download | cpython-7a6054b19dae9c65ce7cfe897ac589448972b646.zip cpython-7a6054b19dae9c65ce7cfe897ac589448972b646.tar.gz cpython-7a6054b19dae9c65ce7cfe897ac589448972b646.tar.bz2 |
Minor cleanup of the new scheme for detecting thread termination.
Documented some obscurities, and assert'ed ._stop()'s crucial precondition.
Diffstat (limited to 'Lib/threading.py')
-rw-r--r-- | Lib/threading.py | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/Lib/threading.py b/Lib/threading.py index 1921ee3..9adc2b4 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -703,8 +703,28 @@ class Thread: pass def _stop(self): - self._is_stopped = True - self._tstate_lock = None + # After calling .stop(), .is_alive() returns False and .join() returns + # immediately. ._tstate_lock must be released before calling ._stop(). + # + # Normal case: C code at the end of the thread's life + # (release_sentinel in _threadmodule.c) releases ._tstate_lock, and + # that's detected by our ._wait_for_tstate_lock(), called by .join() + # and .is_alive(). Any number of threads _may_ call ._stop() + # simultaneously (for example, if multiple threads are blocked in + # .join() calls), and they're not serialized. That's harmless - + # they'll just make redundant rebindings of ._is_stopped and + # ._tstate_lock. Obscure: we rebind ._tstate_lock last so that the + # "assert self._is_stopped" in ._wait_for_tstate_lock() always works + # (the assert is executed only if ._tstate_lock is None). + # + # Special case: _main_thread releases ._tstate_lock via this module's + # _shutdown() function. + tlock = self._tstate_lock + if tlock is not None: + # It's OK if multiple threads get in here (see above). + assert not tlock.locked() + self._is_stopped = True + self._tstate_lock = None def _delete(self): "Remove current thread from the dict of currently running threads." @@ -921,9 +941,10 @@ def _shutdown(): # the main thread's tstate_lock - that won't happen until the interpreter # is nearly dead. So we release it here. Note that just calling _stop() # isn't enough: other threads may already be waiting on _tstate_lock. - assert _main_thread._tstate_lock is not None - assert _main_thread._tstate_lock.locked() - _main_thread._tstate_lock.release() + tlock = _main_thread._tstate_lock + assert tlock is not None + assert tlock.locked() + tlock.release() _main_thread._stop() t = _pickSomeNonDaemonThread() while t: |