https://github.com/python/cpython/commit/329865b883c4c51026c6abe656f2c0e83fed2c4e
commit: 329865b883c4c51026c6abe656f2c0e83fed2c4e
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2024-11-22T17:08:18Z
summary:

[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 1848ce61f349533ae5892a8c24c2e0e3c364fc8a)

Co-authored-by: Andrei Bodrov <[email protected]>
Co-authored-by: Serhiy Storchaka <[email protected]>

files:
A Misc/NEWS.d/next/Library/2023-02-15-23-54-42.gh-issue-88110.KU6erv.rst
M Lib/concurrent/futures/thread.py
M Lib/test/test_concurrent_futures/test_thread_pool.py

diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py
index a024033f35fb54..9021dde48ef1e4 100644
--- a/Lib/concurrent/futures/thread.py
+++ b/Lib/concurrent/futures/thread.py
@@ -41,6 +41,7 @@ def _python_exit():
     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:
diff --git a/Lib/test/test_concurrent_futures/test_thread_pool.py 
b/Lib/test/test_concurrent_futures/test_thread_pool.py
index 2b5bea9f4055a2..4324241b374967 100644
--- a/Lib/test/test_concurrent_futures/test_thread_pool.py
+++ b/Lib/test/test_concurrent_futures/test_thread_pool.py
@@ -66,6 +66,25 @@ def submit(pool):
                 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 = []
diff --git 
a/Misc/NEWS.d/next/Library/2023-02-15-23-54-42.gh-issue-88110.KU6erv.rst 
b/Misc/NEWS.d/next/Library/2023-02-15-23-54-42.gh-issue-88110.KU6erv.rst
new file mode 100644
index 00000000000000..42a83edc3ba68d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-02-15-23-54-42.gh-issue-88110.KU6erv.rst
@@ -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`.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to