mirror of
https://github.com/python/cpython.git
synced 2024-11-23 01:45:25 +08:00
[3.13] gh-88110: Clear concurrent.futures.thread._threads_queues after fork to avoid joining parent process' threads (GH-126098) (GH-127163)
Threads are gone after fork, so clear the queues too. Otherwise the
child process (here created via multiprocessing.Process) crashes on
interpreter exit.
(cherry picked from commit 1848ce61f3
)
Co-authored-by: Andrei Bodrov <Drino@users.noreply.github.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
f0d1a20b77
commit
329865b883
@ -41,6 +41,7 @@ if hasattr(os, 'register_at_fork'):
|
||||
os.register_at_fork(before=_global_shutdown_lock.acquire,
|
||||
after_in_child=_global_shutdown_lock._at_fork_reinit,
|
||||
after_in_parent=_global_shutdown_lock.release)
|
||||
os.register_at_fork(after_in_child=_threads_queues.clear)
|
||||
|
||||
|
||||
class _WorkItem:
|
||||
|
@ -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 = []
|
||||
|
@ -0,0 +1,2 @@
|
||||
Fixed :class:`multiprocessing.Process` reporting a ``.exitcode`` of 1 even on success when
|
||||
using the ``"fork"`` start method while using a :class:`concurrent.futures.ThreadPoolExecutor`.
|
Loading…
Reference in New Issue
Block a user