summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 4f49d7f1cb..91f5a8b2df 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 409360dae2..2f472b47aa 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