From c5ea06e5bbffc9e1b8d69d5f4c9fc707f0bbe9ae Mon Sep 17 00:00:00 2001 From: "Jiucheng(Oliver)" Date: Fri, 23 May 2025 15:22:14 -0400 Subject: [PATCH] gh-134381: Fix RuntimeError when starting not-yet started Thread after fork (gh-134514) (cherry picked from commit 9a2346df861f26d5f8d054ad2f9c37134dee3822) Co-authored-by: Jiucheng(Oliver) --- Lib/test/_test_multiprocessing.py | 22 +++++++++++++++++++ ...-05-22-14-48-19.gh-issue-134381.2BXhth.rst | 1 + Modules/_threadmodule.c | 6 +++++ 3 files changed, 29 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 9e3330e40ffaab..0b8de96f1b0c96 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6494,6 +6494,28 @@ def f(x): return x*x self.assertEqual("332833500", out.decode('utf-8').strip()) self.assertFalse(err, msg=err.decode('utf-8')) + def test_forked_thread_not_started(self): + # gh-134381: Ensure that a thread that has not been started yet in + # the parent process can be started within a forked child process. + + if multiprocessing.get_start_method() != "fork": + self.skipTest("fork specific test") + + q = multiprocessing.Queue() + t = threading.Thread(target=lambda: q.put("done"), daemon=True) + + def child(): + t.start() + t.join() + + p = multiprocessing.Process(target=child) + p.start() + p.join(support.SHORT_TIMEOUT) + + self.assertEqual(p.exitcode, 0) + self.assertEqual(q.get_nowait(), "done") + close_queue(q) + # # Mixins diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst new file mode 100644 index 00000000000000..aa8900296ae2fc --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst @@ -0,0 +1 @@ +Fix :exc:`RuntimeError` when using a not-started :class:`threading.Thread` after calling :func:`os.fork` diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 2853f3d26773d0..52bb45f1891ac3 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -262,6 +262,12 @@ _PyThread_AfterFork(struct _pythread_runtime_state *state) continue; } + // Keep handles for threads that have not been started yet. They are + // safe to start in the child process. + if (handle->state == THREAD_HANDLE_NOT_STARTED) { + continue; + } + // Mark all threads as done. Any attempts to join or detach the // underlying OS thread (if any) could crash. We are the only thread; // it's safe to set this non-atomically. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy