我在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 *'
答案 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()