[Python-checkins] bpo-18966: non-daemonic threads created by a multiprocessing.Process should be joined on exit (#3111)
Antoine Pitrou
webhook-mailer at python.org
Wed Aug 16 14:53:32 EDT 2017
https://github.com/python/cpython/commit/ee84a608587b930176d37303afae8a4358e15990
commit: ee84a608587b930176d37303afae8a4358e15990
branch: master
author: Antoine Pitrou <pitrou at free.fr>
committer: GitHub <noreply at github.com>
date: 2017-08-16T20:53:28+02:00
summary:
bpo-18966: non-daemonic threads created by a multiprocessing.Process should be joined on exit (#3111)
* bpo-18966: non-daemonic threads created by a multiprocessing.Process should be joined on exit
* Add NEWS blurb
files:
A Misc/NEWS.d/next/Library/2017-08-16-20-28-06.bpo-18966.mjHWk2.rst
M Lib/multiprocessing/process.py
M Lib/test/_test_multiprocessing.py
M Lib/threading.py
diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py
index 8e500dc93dc..8fff3e105ea 100644
--- a/Lib/multiprocessing/process.py
+++ b/Lib/multiprocessing/process.py
@@ -17,6 +17,7 @@
import sys
import signal
import itertools
+import threading
from _weakrefset import WeakSet
#
@@ -311,6 +312,7 @@ def _bootstrap(self):
sys.stderr.write('Process %s:\n' % self.name)
traceback.print_exc()
finally:
+ threading._shutdown()
util.info('process exiting with exitcode %d' % exitcode)
sys.stdout.flush()
sys.stderr.flush()
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index dce62df1d02..d6fe7d62675 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -542,6 +542,32 @@ def test_child_fd_inflation(self):
p.join()
close_queue(q)
+ @classmethod
+ def _test_wait_for_threads(self, evt):
+ def func1():
+ time.sleep(0.5)
+ evt.set()
+
+ def func2():
+ time.sleep(20)
+ evt.clear()
+
+ threading.Thread(target=func1).start()
+ threading.Thread(target=func2, daemon=True).start()
+
+ def test_wait_for_threads(self):
+ # A child process should wait for non-daemonic threads to end
+ # before exiting
+ if self.TYPE == 'threads':
+ self.skipTest('test not appropriate for {}'.format(self.TYPE))
+
+ evt = self.Event()
+ proc = self.Process(target=self._test_wait_for_threads, args=(evt,))
+ proc.start()
+ proc.join()
+ self.assertTrue(evt.is_set())
+
+
#
#
#
diff --git a/Lib/threading.py b/Lib/threading.py
index 92c2ab365b4..06dbc682834 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -1284,6 +1284,9 @@ def _shutdown():
# the main thread's tstate_lock - that won't happen until the interpreter
# is nearly dead. So we release it here. Note that just calling _stop()
# isn't enough: other threads may already be waiting on _tstate_lock.
+ if _main_thread._is_stopped:
+ # _shutdown() was already called
+ return
tlock = _main_thread._tstate_lock
# The main thread isn't finished yet, so its thread state lock can't have
# been released.
diff --git a/Misc/NEWS.d/next/Library/2017-08-16-20-28-06.bpo-18966.mjHWk2.rst b/Misc/NEWS.d/next/Library/2017-08-16-20-28-06.bpo-18966.mjHWk2.rst
new file mode 100644
index 00000000000..53bea710127
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-08-16-20-28-06.bpo-18966.mjHWk2.rst
@@ -0,0 +1,2 @@
+Non-daemonic threads created by a multiprocessing.Process are now joined on
+child exit.
More information about the Python-checkins
mailing list