Issue #15881: Fixed atexit hook in multiprocessing.

This commit is contained in:
Alexander Belopolsky 2012-09-09 13:20:58 -04:00
parent 5497295917
commit f36c49d124
2 changed files with 32 additions and 8 deletions

View File

@ -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

View File

@ -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,6 +288,17 @@ 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)
if current_process() is not None:
# We check if the current process is None here because if
# it's None, any call to ``active_children()`` will throw an
# 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():
if p._daemonic: if p._daemonic:
info('calling terminate() for daemon %s', p.name) info('calling terminate() for daemon %s', p.name)