@@ -908,7 +908,6 @@ class is implemented.
908908 self ._ident = None
909909 if _HAVE_THREAD_NATIVE_ID :
910910 self ._native_id = None
911- self ._running_lock = None
912911 self ._tstate_lock = None
913912 self ._started = Event ()
914913 self ._is_stopped = False
@@ -927,17 +926,13 @@ def _reset_internal_locks(self, is_alive):
927926 # bpo-42350: If the fork happens when the thread is already stopped
928927 # (ex: after threading._shutdown() has been called), _tstate_lock
929928 # is None. Do nothing in this case.
930- if self ._running_lock is not None :
931- self ._running_lock ._at_fork_reinit ()
932- self ._running_lock .acquire ()
933929 if self ._tstate_lock is not None :
934930 self ._tstate_lock ._at_fork_reinit ()
935931 self ._tstate_lock .acquire ()
936932 else :
937933 # The thread isn't alive after fork: it doesn't have a tstate
938934 # anymore.
939935 self ._is_stopped = True
940- self ._running_lock = None
941936 self ._tstate_lock = None
942937
943938 def __repr__ (self ):
@@ -1024,14 +1019,6 @@ def _set_ident(self):
10241019 def _set_native_id (self ):
10251020 self ._native_id = get_native_id ()
10261021
1027- def _set_running_lock (self ):
1028- """
1029- Set a lock object which will be released by the interpreter when
1030- the target func has finished running.
1031- """
1032- self ._running_lock = _allocate_lock ()
1033- self ._running_lock .acquire ()
1034-
10351022 def _set_tstate_lock (self ):
10361023 """
10371024 Set a lock object which will be released by the interpreter when
@@ -1048,7 +1035,6 @@ def _set_tstate_lock(self):
10481035 def _bootstrap_inner (self ):
10491036 try :
10501037 self ._set_ident ()
1051- self ._set_running_lock ()
10521038 self ._set_tstate_lock ()
10531039 if _HAVE_THREAD_NATIVE_ID :
10541040 self ._set_native_id ()
@@ -1068,29 +1054,29 @@ def _bootstrap_inner(self):
10681054 self ._invoke_excepthook (self )
10691055 finally :
10701056 self ._delete ()
1071- self ._running_lock .release ()
10721057
10731058 def _stop (self ):
10741059 # After calling ._stop(), .is_alive() returns False and .join() returns
1075- # immediately. ._running_lock must be released before calling ._stop().
1060+ # immediately. ._tstate_lock must be released before calling ._stop().
10761061 #
1077- # Normal case: ._bootstrap_inner() releases ._running_lock, and
1078- # that's detected by our ._wait_for_running_lock(), called by .join()
1062+ # Normal case: C code at the end of the thread's life
1063+ # (release_sentinel in _threadmodule.c) releases ._tstate_lock, and
1064+ # that's detected by our ._wait_for_tstate_lock(), called by .join()
10791065 # and .is_alive(). Any number of threads _may_ call ._stop()
10801066 # simultaneously (for example, if multiple threads are blocked in
10811067 # .join() calls), and they're not serialized. That's harmless -
10821068 # they'll just make redundant rebindings of ._is_stopped and
1083- # ._running_lock . Obscure: we rebind ._running_lock last so that the
1084- # "assert self._is_stopped" in ._wait_for_running_lock () always works
1085- # (the assert is executed only if ._running_lock is None).
1069+ # ._tstate_lock . Obscure: we rebind ._tstate_lock last so that the
1070+ # "assert self._is_stopped" in ._wait_for_tstate_lock () always works
1071+ # (the assert is executed only if ._tstate_lock is None).
10861072 #
1087- # Special case: _main_thread releases ._running_lock via this
1073+ # Special case: _main_thread releases ._tstate_lock via this
10881074 # module's _shutdown() function.
1089- lock = self ._running_lock
1075+ lock = self ._tstate_lock
10901076 if lock is not None :
10911077 assert not lock .locked ()
10921078 self ._is_stopped = True
1093- self ._running_lock = None
1079+ self ._tstate_lock = None
10941080 if not self .daemon :
10951081 with _shutdown_locks_lock :
10961082 # Remove our lock and other released locks from _shutdown_locks
@@ -1137,17 +1123,20 @@ def join(self, timeout=None):
11371123 raise RuntimeError ("cannot join current thread" )
11381124
11391125 if timeout is None :
1140- self ._wait_for_running_lock ()
1126+ self ._wait_for_tstate_lock ()
11411127 else :
11421128 # the behavior of a negative timeout isn't documented, but
11431129 # historically .join(timeout=x) for x<0 has acted as if timeout=0
1144- self ._wait_for_running_lock (timeout = max (timeout , 0 ))
1145-
1146- def _wait_for_running_lock (self , block = True , timeout = - 1 ):
1147- # This method passes its arguments to _running_lock.acquire().
1148- # If the lock is acquired, the python code is done, and self._stop() is
1149- # called. That sets ._is_stopped to True, and ._running_lock to None.
1150- lock = self ._running_lock
1130+ self ._wait_for_tstate_lock (timeout = max (timeout , 0 ))
1131+
1132+ def _wait_for_tstate_lock (self , block = True , timeout = - 1 ):
1133+ # Issue #18808: wait for the thread state to be gone.
1134+ # At the end of the thread's life, after all knowledge of the thread
1135+ # is removed from C data structures, C code releases our _tstate_lock.
1136+ # This method passes its arguments to _tstate_lock.acquire().
1137+ # If the lock is acquired, the C code is done, and self._stop() is
1138+ # called. That sets ._is_stopped to True, and ._tstate_lock to None.
1139+ lock = self ._tstate_lock
11511140 if lock is None :
11521141 # already determined that the C code is done
11531142 assert self ._is_stopped
@@ -1218,7 +1207,7 @@ def is_alive(self):
12181207 assert self ._initialized , "Thread.__init__() not called"
12191208 if self ._is_stopped or not self ._started .is_set ():
12201209 return False
1221- self ._wait_for_running_lock (False )
1210+ self ._wait_for_tstate_lock (False )
12221211 return not self ._is_stopped
12231212
12241213 @property
@@ -1428,7 +1417,7 @@ class _MainThread(Thread):
14281417
14291418 def __init__ (self ):
14301419 Thread .__init__ (self , name = "MainThread" , daemon = False )
1431- self ._set_running_lock ()
1420+ self ._set_tstate_lock ()
14321421 self ._started .set ()
14331422 self ._set_ident ()
14341423 if _HAVE_THREAD_NATIVE_ID :
@@ -1569,7 +1558,7 @@ def _shutdown():
15691558 # dubious, but some code does it. We can't wait for C code to release
15701559 # the main thread's tstate_lock - that won't happen until the interpreter
15711560 # is nearly dead. So we release it here. Note that just calling _stop()
1572- # isn't enough: other threads may already be waiting on _running_lock .
1561+ # isn't enough: other threads may already be waiting on _tstate_lock .
15731562 if _main_thread ._is_stopped :
15741563 # _shutdown() was already called
15751564 return
@@ -1584,13 +1573,12 @@ def _shutdown():
15841573
15851574 # Main thread
15861575 if _main_thread .ident == get_ident ():
1587- assert _main_thread ._tstate_lock is None
1588- running_lock = _main_thread ._running_lock
1589- # The main thread isn't finished yet, so its running lock can't
1576+ tlock = _main_thread ._tstate_lock
1577+ # The main thread isn't finished yet, so its thread state lock can't
15901578 # have been released.
1591- assert running_lock is not None
1592- assert running_lock .locked ()
1593- running_lock .release ()
1579+ assert tlock is not None
1580+ assert tlock .locked ()
1581+ tlock .release ()
15941582 _main_thread ._stop ()
15951583 else :
15961584 # bpo-1596321: _shutdown() must be called in the main thread.
0 commit comments