mirror of
https://github.com/python/cpython.git
synced 2025-10-19 16:03:42 +00:00
GH-110829: Ensure Thread.join() joins the OS thread (#110848)
Joining a thread now ensures the underlying OS thread has exited. This is required for safer fork() in multi-threaded processes. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
This commit is contained in:
parent
a28a3967ab
commit
0e9c364f4a
14 changed files with 676 additions and 103 deletions
|
@ -376,8 +376,8 @@ def test_limbo_cleanup(self):
|
|||
# Issue 7481: Failure to start thread should cleanup the limbo map.
|
||||
def fail_new_thread(*args):
|
||||
raise threading.ThreadError()
|
||||
_start_new_thread = threading._start_new_thread
|
||||
threading._start_new_thread = fail_new_thread
|
||||
_start_joinable_thread = threading._start_joinable_thread
|
||||
threading._start_joinable_thread = fail_new_thread
|
||||
try:
|
||||
t = threading.Thread(target=lambda: None)
|
||||
self.assertRaises(threading.ThreadError, t.start)
|
||||
|
@ -385,7 +385,7 @@ def fail_new_thread(*args):
|
|||
t in threading._limbo,
|
||||
"Failed to cleanup _limbo map on failure of Thread.start().")
|
||||
finally:
|
||||
threading._start_new_thread = _start_new_thread
|
||||
threading._start_joinable_thread = _start_joinable_thread
|
||||
|
||||
def test_finalize_running_thread(self):
|
||||
# Issue 1402: the PyGILState_Ensure / _Release functions may be called
|
||||
|
@ -482,6 +482,47 @@ def test_enumerate_after_join(self):
|
|||
finally:
|
||||
sys.setswitchinterval(old_interval)
|
||||
|
||||
def test_join_from_multiple_threads(self):
|
||||
# Thread.join() should be thread-safe
|
||||
errors = []
|
||||
|
||||
def worker():
|
||||
time.sleep(0.005)
|
||||
|
||||
def joiner(thread):
|
||||
try:
|
||||
thread.join()
|
||||
except Exception as e:
|
||||
errors.append(e)
|
||||
|
||||
for N in range(2, 20):
|
||||
threads = [threading.Thread(target=worker)]
|
||||
for i in range(N):
|
||||
threads.append(threading.Thread(target=joiner,
|
||||
args=(threads[0],)))
|
||||
for t in threads:
|
||||
t.start()
|
||||
time.sleep(0.01)
|
||||
for t in threads:
|
||||
t.join()
|
||||
if errors:
|
||||
raise errors[0]
|
||||
|
||||
def test_join_with_timeout(self):
|
||||
lock = _thread.allocate_lock()
|
||||
lock.acquire()
|
||||
|
||||
def worker():
|
||||
lock.acquire()
|
||||
|
||||
thread = threading.Thread(target=worker)
|
||||
thread.start()
|
||||
thread.join(timeout=0.01)
|
||||
assert thread.is_alive()
|
||||
lock.release()
|
||||
thread.join()
|
||||
assert not thread.is_alive()
|
||||
|
||||
def test_no_refcycle_through_target(self):
|
||||
class RunSelfFunction(object):
|
||||
def __init__(self, should_raise):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue