summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@gmail.com>2008-02-23 19:40:54 (GMT)
committerJeffrey Yasskin <jyasskin@gmail.com>2008-02-23 19:40:54 (GMT)
commit3414ea9ed9fce2b9ce74e8b6c7c3b4278b526685 (patch)
tree8a4e5b603996a8a72c4f6436f1954c23b17e0fad /Lib
parent1beea27299b836fd9194b769f2f79913ed20219e (diff)
downloadcpython-3414ea9ed9fce2b9ce74e8b6c7c3b4278b526685.zip
cpython-3414ea9ed9fce2b9ce74e8b6c7c3b4278b526685.tar.gz
cpython-3414ea9ed9fce2b9ce74e8b6c7c3b4278b526685.tar.bz2
Prevent classes like:
class RunSelfFunction(object): def __init__(self): self.thread = threading.Thread(target=self._run) self.thread.start() def _run(self): pass from creating a permanent cycle between the object and the thread by having the Thread delete its references to the object when it completes. As an example of the effect of this bug, paramiko.Transport inherits from Thread to avoid it.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_threading.py20
-rw-r--r--Lib/threading.py3
2 files changed, 23 insertions, 0 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 4f49d7f..91f5a8b 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -8,6 +8,7 @@ import threading
import thread
import time
import unittest
+import weakref
# A trivial mutable counter.
class Counter(object):
@@ -253,6 +254,25 @@ class ThreadTests(unittest.TestCase):
finally:
sys.setcheckinterval(old_interval)
+ def test_no_refcycle_through_target(self):
+ class RunSelfFunction(object):
+ def __init__(self):
+ # The links in this refcycle from Thread back to self
+ # should be cleaned up when the thread completes.
+ self.thread = threading.Thread(target=self._run,
+ args=(self,),
+ kwargs={'yet_another':self})
+ self.thread.start()
+
+ def _run(self, other_ref, yet_another):
+ pass
+
+ cyclic_object = RunSelfFunction()
+ weak_cyclic_object = weakref.ref(cyclic_object)
+ cyclic_object.thread.join()
+ del cyclic_object
+ self.assertEquals(None, weak_cyclic_object())
+
class ThreadingExceptionTests(unittest.TestCase):
# A RuntimeError should be raised if Thread.start() is called
diff --git a/Lib/threading.py b/Lib/threading.py
index 409360d..2f472b4 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -444,6 +444,9 @@ class Thread(_Verbose):
def run(self):
if self.__target:
self.__target(*self.__args, **self.__kwargs)
+ # Avoid a refcycle if the thread is running a function with an
+ # argument that has a member that points to the thread.
+ del self.__target, self.__args, self.__kwargs
def __bootstrap(self):
# Wrapper around the real bootstrap code that ignores