Skip to content

Commit e2f440f

Browse files
committed
Fix race condition in Thread.join()
1 parent 447d655 commit e2f440f

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

Lib/test/test_threading.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,32 @@ def test_enumerate_after_join(self):
482482
finally:
483483
sys.setswitchinterval(old_interval)
484484

485+
def test_join_from_multiple_threads(self):
486+
# Thread.join() should be thread-safe
487+
errors = []
488+
489+
def worker():
490+
time.sleep(0.005)
491+
492+
def joiner(thread):
493+
try:
494+
thread.join()
495+
except Exception as e:
496+
errors.append(e)
497+
498+
for N in range(2, 20):
499+
threads = [threading.Thread(target=worker)]
500+
for i in range(N):
501+
threads.append(threading.Thread(target=joiner,
502+
args=(threads[0],)))
503+
for t in threads:
504+
t.start()
505+
time.sleep(0.01)
506+
for t in threads:
507+
t.join()
508+
if errors:
509+
raise errors[0]
510+
485511
def test_no_refcycle_through_target(self):
486512
class RunSelfFunction(object):
487513
def __init__(self, should_raise):

Lib/threading.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,13 +1165,15 @@ def join(self, timeout=None):
11651165

11661166
def _join_os_thread(self):
11671167
join_lock = self._join_lock
1168-
if join_lock is not None:
1169-
# Calling join() multiple times simultaneously would result in early
1170-
# return for one of the callers.
1171-
with join_lock:
1168+
if join_lock is None:
1169+
return
1170+
with join_lock:
1171+
# Calling join() multiple times simultaneously would raise
1172+
# an exception in one of the callers.
1173+
if self._join_lock is not None:
11721174
_join_thread(self._ident)
1173-
self._join_lock = None
1174-
self._non_joined_finalizer = None
1175+
self._join_lock = None
1176+
self._non_joined_finalizer = None
11751177

11761178
def _wait_for_tstate_lock(self, block=True, timeout=-1):
11771179
# Issue #18808: wait for the thread state to be gone.

0 commit comments

Comments
 (0)