gh-140814: Fix freeze_support() setting start method as side effect (GH-144608)
freeze_support() called get_start_method() without allow_none=True,
which locked in the default start method context. This caused a
subsequent set_start_method() call to raise "context has already been
set". Use allow_none=True and accept None as a matching value, since
spawn.freeze_support() independently detects spawned child processes.
Test that freeze_support() does not lock in the default start method,
which would prevent a subsequent set_start_method() call.
(cherry picked from commit
ee5318025b0f9f4d30d9358627df68181e0d223f)
Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
'''Check whether this is a fake forked process in a frozen executable.
If so then run code specified by commandline and exit.
'''
- if self.get_start_method() == 'spawn' and getattr(sys, 'frozen', False):
+ # gh-140814: allow_none=True avoids locking in the default start
+ # method, which would cause a later set_start_method() to fail.
+ # None is safe to pass through: spawn.freeze_support()
+ # independently detects whether this process is a spawned
+ # child, so the start method check here is only an optimization.
+ if (getattr(sys, 'frozen', False)
+ and self.get_start_method(allow_none=True) in ('spawn', None)):
from .spawn import freeze_support
freeze_support()
process.join()
self.assertIsNone(multiprocessing.get_start_method(allow_none=True))
+ @only_run_in_spawn_testsuite("freeze_support is not start method specific")
+ def test_freeze_support_dont_set_context(self):
+ # gh-140814: freeze_support() should not set the start method
+ # as a side effect, so a later set_start_method() still works.
+ multiprocessing.set_start_method(None, force=True)
+ try:
+ multiprocessing.freeze_support()
+ self.assertIsNone(
+ multiprocessing.get_start_method(allow_none=True))
+ # Should not raise "context has already been set"
+ multiprocessing.set_start_method('spawn')
+ finally:
+ multiprocessing.set_start_method(None, force=True)
+
def test_context_check_module_types(self):
try:
ctx = multiprocessing.get_context('forkserver')
--- /dev/null
+:func:`multiprocessing.freeze_support` no longer sets the default start method
+as a side effect, which previously caused a subsequent
+:func:`multiprocessing.set_start_method` call to raise :exc:`RuntimeError`.