Bug report
Checklist
CPython versions tested on:
3.11
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.11.5 (main, Aug 26 2023, 00:26:34) [GCC 12.2.1 20220924]
A clear and concise description of the bug:
Using nested multiprocessing (i.e. spawn a child process inside a child process) is broken as of Python 3.11.5, leading to an attribute error.
ProcessProcess-1:
Traceback (mostrecentcalllast):
File"/usr/local/lib/python3.11/multiprocessing/process.py", line314, in_bootstrapself.run()
File"/usr/local/lib/python3.11/multiprocessing/process.py", line108, inrunself._target(*self._args, **self._kwargs)
File"/io/pyi_multiprocessing_nested_process.py", line15, inprocess_functionprocess.start()
File"/usr/local/lib/python3.11/multiprocessing/process.py", line121, instartself._popen=self._Popen(self)
^^^^^^^^^^^^^^^^^File"/usr/local/lib/python3.11/multiprocessing/context.py", line224, in_Popenreturn_default_context.get_context().Process._Popen(process_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File"/usr/local/lib/python3.11/multiprocessing/context.py", line288, in_PopenreturnPopen(process_obj)
^^^^^^^^^^^^^^^^^^File"/usr/local/lib/python3.11/multiprocessing/popen_spawn_posix.py", line32, in__init__super().__init__(process_obj)
File"/usr/local/lib/python3.11/multiprocessing/popen_fork.py", line19, in__init__self._launch(process_obj)
File"/usr/local/lib/python3.11/multiprocessing/popen_spawn_posix.py", line47, in_launchreduction.dump(process_obj, fp)
File"/usr/local/lib/python3.11/multiprocessing/reduction.py", line60, indumpForkingPickler(file, protocol).dump(obj)
File"/usr/local/lib/python3.11/multiprocessing/synchronize.py", line106, in__getstate__ifself.is_fork_ctx:
^^^^^^^^^^^^^^^^AttributeError: 'Lock'objecthasnoattribute'is_fork_ctx'Results: [1]
Minimal code example below. Invoke with argument fork, forkserver or spawn. fork will work. forkserver and spawn will both raise the above error. All three variants work with Python 3.11.4.
importsysimportmultiprocessingdefnested_process_function(queue):
print("Running nested sub-process!")
queue.put(2)
defprocess_function(queue):
print("Running sub-process!")
queue.put(1)
process=multiprocessing.Process(target=nested_process_function, args=(queue,))
process.start()
process.join()
defmain(start_method):
multiprocessing.set_start_method(start_method)
queue=multiprocessing.Queue()
process=multiprocessing.Process(target=process_function, args=(queue,))
process.start()
process.join()
results= []
whilenotqueue.empty():
results.append(queue.get())
print(f"Results: {results}")
assertresults== [1, 2]
if__name__=='__main__':
iflen(sys.argv) !=2:
raiseSystemExit(f"Usage: {sys.argv[0]} fork|forkserver|spawn")
main(sys.argv[1])I believe that the source of this regression is 34ef75d which adds the attribute is_fork_ctx to multiprocessing.Lock() but doesn't update the pickle methods (__getstate__() and __setstate__()) so after being serialised and deserialised, the Lock() object looses that attribute.
The following patch, adding is_fork_ctx to the pickle methods, makes the above work again.
diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py
index 2328d33212..9c5c2aada6 100644
--- a/Lib/multiprocessing/synchronize.py+++ b/Lib/multiprocessing/synchronize.py@@ -109,10 +109,11 @@ def __getstate__(self):
'not supported. Please use the same context to create '
'multiprocessing objects and Process.')
h = sl.handle
- return (h, sl.kind, sl.maxvalue, sl.name)+ return (h, sl.kind, sl.maxvalue, sl.name, self.is_fork_ctx)
def __setstate__(self, state):
- self._semlock = _multiprocessing.SemLock._rebuild(*state)+ self._semlock = _multiprocessing.SemLock._rebuild(*state[:4])+ self.is_fork_ctx = state[4]
util.debug('recreated blocker with handle %r' % state[0])
self._make_methods()Linked PRs
Bug report
Checklist
and am confident this bug has not been reported before
CPython versions tested on:
3.11
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.11.5 (main, Aug 26 2023, 00:26:34) [GCC 12.2.1 20220924]
A clear and concise description of the bug:
Using nested
multiprocessing(i.e. spawn a child process inside a child process) is broken as of Python 3.11.5, leading to an attribute error.Minimal code example below. Invoke with argument
fork,forkserverorspawn.forkwill work.forkserverandspawnwill both raise the above error. All three variants work with Python 3.11.4.I believe that the source of this regression is 34ef75d which adds the attribute
is_fork_ctxtomultiprocessing.Lock()but doesn't update the pickle methods (__getstate__()and__setstate__()) so after being serialised and deserialised, theLock()object looses that attribute.The following patch, adding
is_fork_ctxto the pickle methods, makes the above work again.Linked PRs