@@ -908,6 +908,7 @@ class is implemented.
908
908
self ._ident = None
909
909
if _HAVE_THREAD_NATIVE_ID :
910
910
self ._native_id = None
911
+ self ._running_lock = None
911
912
self ._tstate_lock = None
912
913
self ._started = Event ()
913
914
self ._is_stopped = False
@@ -926,13 +927,17 @@ def _reset_internal_locks(self, is_alive):
926
927
# bpo-42350: If the fork happens when the thread is already stopped
927
928
# (ex: after threading._shutdown() has been called), _tstate_lock
928
929
# 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 ()
929
933
if self ._tstate_lock is not None :
930
934
self ._tstate_lock ._at_fork_reinit ()
931
935
self ._tstate_lock .acquire ()
932
936
else :
933
937
# The thread isn't alive after fork: it doesn't have a tstate
934
938
# anymore.
935
939
self ._is_stopped = True
940
+ self ._running_lock = None
936
941
self ._tstate_lock = None
937
942
938
943
def __repr__ (self ):
@@ -1019,6 +1024,14 @@ def _set_ident(self):
1019
1024
def _set_native_id (self ):
1020
1025
self ._native_id = get_native_id ()
1021
1026
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
+
1022
1035
def _set_tstate_lock (self ):
1023
1036
"""
1024
1037
Set a lock object which will be released by the interpreter when
@@ -1035,6 +1048,7 @@ def _set_tstate_lock(self):
1035
1048
def _bootstrap_inner (self ):
1036
1049
try :
1037
1050
self ._set_ident ()
1051
+ self ._set_running_lock ()
1038
1052
self ._set_tstate_lock ()
1039
1053
if _HAVE_THREAD_NATIVE_ID :
1040
1054
self ._set_native_id ()
@@ -1054,29 +1068,29 @@ def _bootstrap_inner(self):
1054
1068
self ._invoke_excepthook (self )
1055
1069
finally :
1056
1070
self ._delete ()
1071
+ self ._running_lock .release ()
1057
1072
1058
1073
def _stop (self ):
1059
1074
# After calling ._stop(), .is_alive() returns False and .join() returns
1060
- # immediately. ._tstate_lock must be released before calling ._stop().
1075
+ # immediately. ._running_lock must be released before calling ._stop().
1061
1076
#
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()
1077
+ # Normal case: ._bootstrap_inner() releases ._running_lock, and
1078
+ # that's detected by our ._wait_for_running_lock(), called by .join()
1065
1079
# and .is_alive(). Any number of threads _may_ call ._stop()
1066
1080
# simultaneously (for example, if multiple threads are blocked in
1067
1081
# .join() calls), and they're not serialized. That's harmless -
1068
1082
# they'll just make redundant rebindings of ._is_stopped and
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).
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).
1072
1086
#
1073
- # Special case: _main_thread releases ._tstate_lock via this
1087
+ # Special case: _main_thread releases ._running_lock via this
1074
1088
# module's _shutdown() function.
1075
- lock = self ._tstate_lock
1089
+ lock = self ._running_lock
1076
1090
if lock is not None :
1077
1091
assert not lock .locked ()
1078
1092
self ._is_stopped = True
1079
- self ._tstate_lock = None
1093
+ self ._running_lock = None
1080
1094
if not self .daemon :
1081
1095
with _shutdown_locks_lock :
1082
1096
# Remove our lock and other released locks from _shutdown_locks
@@ -1123,20 +1137,17 @@ def join(self, timeout=None):
1123
1137
raise RuntimeError ("cannot join current thread" )
1124
1138
1125
1139
if timeout is None :
1126
- self ._wait_for_tstate_lock ()
1140
+ self ._wait_for_running_lock ()
1127
1141
else :
1128
1142
# the behavior of a negative timeout isn't documented, but
1129
1143
# historically .join(timeout=x) for x<0 has acted as if timeout=0
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
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
1140
1151
if lock is None :
1141
1152
# already determined that the C code is done
1142
1153
assert self ._is_stopped
@@ -1207,7 +1218,7 @@ def is_alive(self):
1207
1218
assert self ._initialized , "Thread.__init__() not called"
1208
1219
if self ._is_stopped or not self ._started .is_set ():
1209
1220
return False
1210
- self ._wait_for_tstate_lock (False )
1221
+ self ._wait_for_running_lock (False )
1211
1222
return not self ._is_stopped
1212
1223
1213
1224
@property
@@ -1417,7 +1428,7 @@ class _MainThread(Thread):
1417
1428
1418
1429
def __init__ (self ):
1419
1430
Thread .__init__ (self , name = "MainThread" , daemon = False )
1420
- self ._set_tstate_lock ()
1431
+ self ._set_running_lock ()
1421
1432
self ._started .set ()
1422
1433
self ._set_ident ()
1423
1434
if _HAVE_THREAD_NATIVE_ID :
@@ -1558,7 +1569,7 @@ def _shutdown():
1558
1569
# dubious, but some code does it. We can't wait for C code to release
1559
1570
# the main thread's tstate_lock - that won't happen until the interpreter
1560
1571
# is nearly dead. So we release it here. Note that just calling _stop()
1561
- # isn't enough: other threads may already be waiting on _tstate_lock .
1572
+ # isn't enough: other threads may already be waiting on _running_lock .
1562
1573
if _main_thread ._is_stopped :
1563
1574
# _shutdown() was already called
1564
1575
return
@@ -1573,12 +1584,13 @@ def _shutdown():
1573
1584
1574
1585
# Main thread
1575
1586
if _main_thread .ident == get_ident ():
1576
- tlock = _main_thread ._tstate_lock
1577
- # The main thread isn't finished yet, so its thread state lock can't
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
1578
1590
# have been released.
1579
- assert tlock is not None
1580
- assert tlock .locked ()
1581
- tlock .release ()
1591
+ assert running_lock is not None
1592
+ assert running_lock .locked ()
1593
+ running_lock .release ()
1582
1594
_main_thread ._stop ()
1583
1595
else :
1584
1596
# bpo-1596321: _shutdown() must be called in the main thread.
0 commit comments