Skip to content

Commit ee53180

Browse files
gpsheadclaudepicnixz
authored
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. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent 40095d5 commit ee53180

File tree

3 files changed

+24
-1
lines changed

3 files changed

+24
-1
lines changed

Lib/multiprocessing/context.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,13 @@ def freeze_support(self):
145145
'''Check whether this is a fake forked process in a frozen executable.
146146
If so then run code specified by commandline and exit.
147147
'''
148-
if self.get_start_method() == 'spawn' and getattr(sys, 'frozen', False):
148+
# gh-140814: allow_none=True avoids locking in the default start
149+
# method, which would cause a later set_start_method() to fail.
150+
# None is safe to pass through: spawn.freeze_support()
151+
# independently detects whether this process is a spawned
152+
# child, so the start method check here is only an optimization.
153+
if (getattr(sys, 'frozen', False)
154+
and self.get_start_method(allow_none=True) in ('spawn', None)):
149155
from .spawn import freeze_support
150156
freeze_support()
151157

Lib/test/_test_multiprocessing.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6005,6 +6005,20 @@ def test_spawn_dont_set_context(self):
60056005
process.join()
60066006
self.assertIsNone(multiprocessing.get_start_method(allow_none=True))
60076007

6008+
@only_run_in_spawn_testsuite("freeze_support is not start method specific")
6009+
def test_freeze_support_dont_set_context(self):
6010+
# gh-140814: freeze_support() should not set the start method
6011+
# as a side effect, so a later set_start_method() still works.
6012+
multiprocessing.set_start_method(None, force=True)
6013+
try:
6014+
multiprocessing.freeze_support()
6015+
self.assertIsNone(
6016+
multiprocessing.get_start_method(allow_none=True))
6017+
# Should not raise "context has already been set"
6018+
multiprocessing.set_start_method('spawn')
6019+
finally:
6020+
multiprocessing.set_start_method(None, force=True)
6021+
60086022
def test_context_check_module_types(self):
60096023
try:
60106024
ctx = multiprocessing.get_context('forkserver')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`multiprocessing.freeze_support` no longer sets the default start method
2+
as a side effect, which previously caused a subsequent
3+
:func:`multiprocessing.set_start_method` call to raise :exc:`RuntimeError`.

0 commit comments

Comments
 (0)