diff options
author | Richard Oudkerk <shibturn@gmail.com> | 2013-04-17 18:15:52 (GMT) |
---|---|---|
committer | Richard Oudkerk <shibturn@gmail.com> | 2013-04-17 18:15:52 (GMT) |
commit | 7bdd93c20e2751420a4a51d019f6887e972d783e (patch) | |
tree | 2a15b9f20b207ee1747e4c1364534e5e12e9d751 | |
parent | 90f8b23be293712447a67f41b58e19cd7b803ad5 (diff) | |
download | cpython-7bdd93c20e2751420a4a51d019f6887e972d783e.zip cpython-7bdd93c20e2751420a4a51d019f6887e972d783e.tar.gz cpython-7bdd93c20e2751420a4a51d019f6887e972d783e.tar.bz2 |
Issue #17555: Fix ForkAwareThreadLock so that size of after fork
registry does not grow exponentially with generation of process.
-rw-r--r-- | Lib/multiprocessing/util.py | 5 | ||||
-rw-r--r-- | Lib/test/test_multiprocessing.py | 32 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
3 files changed, 38 insertions, 2 deletions
diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py index 3ce480f..d1b3d2e 100644 --- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -329,10 +329,13 @@ atexit.register(_exit_function) class ForkAwareThreadLock(object): def __init__(self): + self._reset() + register_after_fork(self, ForkAwareThreadLock._reset) + + def _reset(self): self._lock = threading.Lock() self.acquire = self._lock.acquire self.release = self._lock.release - register_after_fork(self, ForkAwareThreadLock.__init__) class ForkAwareLocal(threading.local): def __init__(self): diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py index bdf4e62..88663ef 100644 --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -2430,13 +2430,43 @@ class TestFlags(unittest.TestCase): [sys.executable, '-E', '-B', '-O', '-c', prog]) child_flags, grandchild_flags = json.loads(data.decode('ascii')) self.assertEqual(child_flags, grandchild_flags) + +# +# Issue #17555: ForkAwareThreadLock +# + +class TestForkAwareThreadLock(unittest.TestCase): + # We recurisvely start processes. Issue #17555 meant that the + # after fork registry would get duplicate entries for the same + # lock. The size of the registry at generation n was ~2**n. + + @classmethod + def child(cls, n, conn): + if n > 1: + p = multiprocessing.Process(target=cls.child, args=(n-1, conn)) + p.start() + p.join() + else: + conn.send(len(util._afterfork_registry)) + conn.close() + + def test_lock(self): + r, w = multiprocessing.Pipe(False) + l = util.ForkAwareThreadLock() + old_size = len(util._afterfork_registry) + p = multiprocessing.Process(target=self.child, args=(5, w)) + p.start() + new_size = r.recv() + p.join() + self.assertLessEqual(new_size, old_size) + # # # testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, TestStdinBadfiledescriptor, TestTimeouts, TestNoForkBomb, - TestFlags] + TestFlags, TestForkAwareThreadLock] # # @@ -28,6 +28,9 @@ Core and Builtins Library ------- +- Issue #17555: Fix ForkAwareThreadLock so that size of after fork + registry does not grow exponentially with generation of process. + - Issue #17710: Fix cPickle raising a SystemError on bogus input. - Issue #17341: Include the invalid name in the error messages from re about |