gh-88110: Clear concurrent.futures.thread._threads_queues after fork to avoid joining parent process' threads (GH-126098)

Threads are gone after fork, so clear the queues too. Otherwise the
child process (here created via multiprocessing.Process) crashes on
interpreter exit.

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Andrei Bodrov 2024-11-22 19:20:34 +03:00 committed by GitHub
parent 7725c0371a
commit 1848ce61f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 0 deletions

View file

@ -66,6 +66,25 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase):
with futures.ProcessPoolExecutor(1, mp_context=mp.get_context('fork')) as workers:
workers.submit(tuple)
@support.requires_fork()
@unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork')
def test_process_fork_from_a_threadpool(self):
# bpo-43944: clear concurrent.futures.thread._threads_queues after fork,
# otherwise child process will try to join parent thread
def fork_process_and_return_exitcode():
# Ignore the warning about fork with threads.
with self.assertWarnsRegex(DeprecationWarning,
r"use of fork\(\) may lead to deadlocks in the child"):
p = mp.get_context('fork').Process(target=lambda: 1)
p.start()
p.join()
return p.exitcode
with futures.ThreadPoolExecutor(1) as pool:
process_exitcode = pool.submit(fork_process_and_return_exitcode).result()
self.assertEqual(process_exitcode, 0)
def test_executor_map_current_future_cancel(self):
stop_event = threading.Event()
log = []