Issue #15881: Fixed atexit hook in multiprocessing.
This commit is contained in:
parent
5497295917
commit
f36c49d124
|
@ -238,3 +238,4 @@ docs@python.org), and we'll be glad to correct the problem.
|
||||||
* Moshe Zadka
|
* Moshe Zadka
|
||||||
* Milan Zamazal
|
* Milan Zamazal
|
||||||
* Cheng Zhang
|
* Cheng Zhang
|
||||||
|
* Chris McDonough
|
||||||
|
|
|
@ -235,6 +235,12 @@ def _run_finalizers(minpriority=None):
|
||||||
Finalizers with highest priority are called first; finalizers with
|
Finalizers with highest priority are called first; finalizers with
|
||||||
the same priority will be called in reverse order of creation.
|
the same priority will be called in reverse order of creation.
|
||||||
'''
|
'''
|
||||||
|
if _finalizer_registry is None:
|
||||||
|
# This function may be called after this module's globals are
|
||||||
|
# destroyed. See the _exit_function function in this module for more
|
||||||
|
# notes.
|
||||||
|
return
|
||||||
|
|
||||||
if minpriority is None:
|
if minpriority is None:
|
||||||
f = lambda p : p[0][0] is not None
|
f = lambda p : p[0][0] is not None
|
||||||
else:
|
else:
|
||||||
|
@ -266,7 +272,13 @@ def is_exiting():
|
||||||
|
|
||||||
_exiting = False
|
_exiting = False
|
||||||
|
|
||||||
def _exit_function():
|
def _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers,
|
||||||
|
active_children=active_children,
|
||||||
|
current_process=current_process):
|
||||||
|
# We hold on to references to functions in the arglist due to the
|
||||||
|
# situation described below, where this function is called after this
|
||||||
|
# module's globals are destroyed.
|
||||||
|
|
||||||
global _exiting
|
global _exiting
|
||||||
|
|
||||||
if not _exiting:
|
if not _exiting:
|
||||||
|
@ -276,14 +288,25 @@ def _exit_function():
|
||||||
debug('running all "atexit" finalizers with priority >= 0')
|
debug('running all "atexit" finalizers with priority >= 0')
|
||||||
_run_finalizers(0)
|
_run_finalizers(0)
|
||||||
|
|
||||||
for p in active_children():
|
if current_process() is not None:
|
||||||
if p._daemonic:
|
# We check if the current process is None here because if
|
||||||
info('calling terminate() for daemon %s', p.name)
|
# it's None, any call to ``active_children()`` will throw an
|
||||||
p._popen.terminate()
|
# AttributeError (active_children winds up trying to get
|
||||||
|
# attributes from util._current_process). This happens in a
|
||||||
|
# variety of shutdown circumstances that are not well-understood
|
||||||
|
# because module-scope variables are not apparently supposed to
|
||||||
|
# be destroyed until after this function is called. However,
|
||||||
|
# they are indeed destroyed before this function is called. See
|
||||||
|
# issues #9775 and #15881. Also related: #4106, #9205, and #9207.
|
||||||
|
|
||||||
for p in active_children():
|
for p in active_children():
|
||||||
info('calling join() for process %s', p.name)
|
if p._daemonic:
|
||||||
p.join()
|
info('calling terminate() for daemon %s', p.name)
|
||||||
|
p._popen.terminate()
|
||||||
|
|
||||||
|
for p in active_children():
|
||||||
|
info('calling join() for process %s', p.name)
|
||||||
|
p.join()
|
||||||
|
|
||||||
debug('running the remaining "atexit" finalizers')
|
debug('running the remaining "atexit" finalizers')
|
||||||
_run_finalizers()
|
_run_finalizers()
|
||||||
|
|
Loading…
Reference in New Issue