Skip to content

Commit a9705b7

Browse files
authored
[3.5] Clear potential ref cycle between Process and Process target (GH-2470) (#2472)
* Clear potential ref cycle between Process and Process target Besides Process.join() not being called, this was an indirect cause of bpo-30775. The threading module already does this. * Add issue reference. (cherry picked from commit 79d37ae)
1 parent f15bf1f commit a9705b7

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

Lib/multiprocessing/process.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ def start(self):
104104
_cleanup()
105105
self._popen = self._Popen(self)
106106
self._sentinel = self._popen.sentinel
107+
# Avoid a refcycle if the target function holds an indirect
108+
# reference to the process object (see bpo-30775)
109+
del self._target, self._args, self._kwargs
107110
_children.add(self)
108111

109112
def terminate(self):

Lib/test/_test_multiprocessing.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ def get_value(self):
191191
# Testcases
192192
#
193193

194+
class DummyCallable:
195+
def __call__(self, q, c):
196+
assert isinstance(c, DummyCallable)
197+
q.put(5)
198+
199+
194200
class _TestProcess(BaseTestCase):
195201

196202
ALLOWED_TYPES = ('processes', 'threads')
@@ -398,6 +404,18 @@ def test_sentinel(self):
398404
p.join()
399405
self.assertTrue(wait_for_handle(sentinel, timeout=1))
400406

407+
def test_lose_target_ref(self):
408+
c = DummyCallable()
409+
wr = weakref.ref(c)
410+
q = self.Queue()
411+
p = self.Process(target=c, args=(q, c))
412+
del c
413+
p.start()
414+
p.join()
415+
self.assertIs(wr(), None)
416+
self.assertEqual(q.get(), 5)
417+
418+
401419
#
402420
#
403421
#

0 commit comments

Comments
 (0)