避免在对象死后调用它

时间:2014-09-29 15:35:57

标签: python multithreading

我在python中有一个threading.Thread子类,其run方法如下:

def run(self):
    while self.caller.isAlive():
        details = self.somefile.read()
        if self.status() and details:
            self.handler(details)
        time.sleep(self.interval)

传递给该帖子的__init__的参数如下:

  • caller是调用者的线程对象
  • status是可调用的,返回指示状态
  • 的布尔值 调用
  • handler来处理细节(某些数据)

while循环检查调用者线程是否处于活动状态。如果是,它进入循环并检查是否有时间进行状态更新并处理数据。它会睡觉并继续循环。请注意,在这种情况下,caller是主线​​程,status由主线程提供(某种函数)。

问题介于while self.caller.isAlive():if self.status() and details:之间。如果调用程序线程在一小段时间内终止,它的status函数仍会被调用,它将引发错误。有什么办法可以防止这种情况吗?

修改 主线程调用此线程。主线程在类中具有状态函数。由于它是一个classmethod,因此必须在调用它时传递实例参数self。就我而言,它就像:

def OnStatus(self, *args, **kwargs):
    ...

当主线程退出(通常)时,类对象及其实例被销毁,但启动的线程仍然存在并可能会调用:

# self.status is self.OnStatus() defined before,
# it is passed as the status callable to init
self.status() # Things might go wrong here (at the wrong time)

修改 用wxpython应用程序尝试了这个并且引发了异常!

'The object that you are referring to is:'
<bound method TextCtrl.IsShown of wxPython wrapper for DELETED TextCtrl object! (The C++ object no longer exists.)>

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/home/user/Desktop/test.py", line 37, in run
    if self.status() and details:
  File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/_core.py", line 9179, in IsShown
    return _core_.Window_IsShown(*args, **kwargs)
TypeError: in method 'Window_IsShown', expected argument 1 of type 'wxWindow const *'

1 个答案:

答案 0 :(得分:0)

在主线程结束后,没有什么能阻止你在调用者上调用status()caller对象仍然存在。它保持活动,因为你的后台线程仍然保持对它的引用,这意味着它的引用计数仍然是非零。考虑这个例子:

import threading
import time

class Ok(threading.Thread):
    def __init__(self, obj):
        super(Ok, self).__init__()
        self.obj = obj

    def run(self):
        while True:
            print self.obj.ok
            time.sleep(2)

class Obj(object):
    def __init__(self):
        self.ok = "hey"


o = Obj()
t = Ok(o)
t.start()
del o

我们在主线程中创建一个Obj的实例,并在它结束之前从主线程中显式删除对它的引用。但是,我们的输出如下:

hey
hey
hey
hey
hey
hey
<forever>

因为后台线程引用了Obj的实例,所以即使主线程完成它也会保持活动状态。

此外,我建议使用Event表示caller线程正在关闭,以便后台Thread一旦发生就会从睡眠中唤醒:

caller_dead = threading.Event()

def run(self):
    while not caller_dead.is_set()
        details = self.somefile.read()
        if self.status() and details:
            self.handler(details)
        caller_dead.wait(self.interval)

....
# This is the end of your main thread
caller_dead.set()