bpo-24484: Avoid race condition in multiprocessing cleanup (#2159)

* bpo-24484: Avoid race condition in multiprocessing cleanup

The finalizer registry can be mutated while inspected by multiprocessing
at process exit.

* Use test.support.start_threads()

* Add Misc/NEWS
This commit is contained in:
Antoine Pitrou 2017-06-13 17:10:39 +02:00 committed by GitHub
parent 8323189ff1
commit 1eb6c0074d
3 changed files with 84 additions and 11 deletions

View file

@ -241,20 +241,28 @@ def _run_finalizers(minpriority=None):
return
if minpriority is None:
f = lambda p : p[0][0] is not None
f = lambda p : p[0] is not None
else:
f = lambda p : p[0][0] is not None and p[0][0] >= minpriority
f = lambda p : p[0] is not None and p[0] >= minpriority
items = [x for x in list(_finalizer_registry.items()) if f(x)]
items.sort(reverse=True)
# Careful: _finalizer_registry may be mutated while this function
# is running (either by a GC run or by another thread).
for key, finalizer in items:
sub_debug('calling %s', finalizer)
try:
finalizer()
except Exception:
import traceback
traceback.print_exc()
# list(_finalizer_registry) should be atomic, while
# list(_finalizer_registry.items()) is not.
keys = [key for key in list(_finalizer_registry) if f(key)]
keys.sort(reverse=True)
for key in keys:
finalizer = _finalizer_registry.get(key)
# key may have been removed from the registry
if finalizer is not None:
sub_debug('calling %s', finalizer)
try:
finalizer()
except Exception:
import traceback
traceback.print_exc()
if minpriority is None:
_finalizer_registry.clear()