避免在对象死后调用它

2024-10-01 17:24:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我在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函数仍然会被调用,并且会引发错误。有什么方法可以防止这种情况发生吗?你知道吗

编辑: 主线程调用这个线程。主线程在类中具有status函数。因为它是类方法,所以在调用它时必须传递实例参数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 *'

Tags: and方法函数runinselfifis
1条回答
网友
1楼 · 发布于 2024-10-01 17:24:27

在主线程结束后,没有什么可以阻止您对调用者调用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()

相关问题 更多 >

    热门问题