Commit a885c152 authored by Jeffrey Yasskin's avatar Jeffrey Yasskin

Followup to r61011: Also avoid the reference cycle when the Thread's target

raises an exception.
parent 3414ea9e
...@@ -256,23 +256,31 @@ class ThreadTests(unittest.TestCase): ...@@ -256,23 +256,31 @@ class ThreadTests(unittest.TestCase):
def test_no_refcycle_through_target(self): def test_no_refcycle_through_target(self):
class RunSelfFunction(object): class RunSelfFunction(object):
def __init__(self): def __init__(self, should_raise):
# The links in this refcycle from Thread back to self # The links in this refcycle from Thread back to self
# should be cleaned up when the thread completes. # should be cleaned up when the thread completes.
self.should_raise = should_raise
self.thread = threading.Thread(target=self._run, self.thread = threading.Thread(target=self._run,
args=(self,), args=(self,),
kwargs={'yet_another':self}) kwargs={'yet_another':self})
self.thread.start() self.thread.start()
def _run(self, other_ref, yet_another): def _run(self, other_ref, yet_another):
pass if self.should_raise:
raise SystemExit
cyclic_object = RunSelfFunction() cyclic_object = RunSelfFunction(should_raise=False)
weak_cyclic_object = weakref.ref(cyclic_object) weak_cyclic_object = weakref.ref(cyclic_object)
cyclic_object.thread.join() cyclic_object.thread.join()
del cyclic_object del cyclic_object
self.assertEquals(None, weak_cyclic_object()) self.assertEquals(None, weak_cyclic_object())
raising_cyclic_object = RunSelfFunction(should_raise=True)
weak_raising_cyclic_object = weakref.ref(raising_cyclic_object)
raising_cyclic_object.thread.join()
del raising_cyclic_object
self.assertEquals(None, weak_raising_cyclic_object())
class ThreadingExceptionTests(unittest.TestCase): class ThreadingExceptionTests(unittest.TestCase):
# A RuntimeError should be raised if Thread.start() is called # A RuntimeError should be raised if Thread.start() is called
......
...@@ -442,11 +442,13 @@ class Thread(_Verbose): ...@@ -442,11 +442,13 @@ class Thread(_Verbose):
_sleep(0.000001) # 1 usec, to let the thread run (Solaris hack) _sleep(0.000001) # 1 usec, to let the thread run (Solaris hack)
def run(self): def run(self):
if self.__target: try:
self.__target(*self.__args, **self.__kwargs) if self.__target:
# Avoid a refcycle if the thread is running a function with an self.__target(*self.__args, **self.__kwargs)
# argument that has a member that points to the thread. finally:
del 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): def __bootstrap(self):
# Wrapper around the real bootstrap code that ignores # Wrapper around the real bootstrap code that ignores
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment