https://github.com/python/cpython/commit/9a2346df861f26d5f8d054ad2f9c37134dee3822
commit: 9a2346df861f26d5f8d054ad2f9c37134dee3822
branch: main
author: Jiucheng(Oliver) <git.jiuch...@gmail.com>
committer: colesbury <colesb...@gmail.com>
date: 2025-05-23T15:22:14-04:00
summary:

gh-134381: Fix RuntimeError when starting not-yet started Thread after fork 
(gh-134514)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst
M Lib/test/_test_multiprocessing.py
M Modules/_threadmodule.c

diff --git a/Lib/test/_test_multiprocessing.py 
b/Lib/test/_test_multiprocessing.py
index 6a20a1eb03e32b..75f31d858d3306 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -6844,6 +6844,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 74b972b201a546..cc83be4b5ff311 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -296,6 +296,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.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to