【问题标题】:python thread exception errors when exit the whole program退出整个程序时python线程异常错误
【发布时间】:2011-05-04 01:10:39
【问题描述】:

大家好,

我正在使用 python 2.4.3 和 wxpython 开发一个 GUI。一切正常,除非我退出主程序(关闭 GUI 的主窗口)。奇怪的是,有时会出现这样的错误,有时根本没有错误。虽然我从 python 邮件列表中找到了相同的错误报告(链接是http://bugs.python.org/issue1722344,我不确定我的情况是否与这个相同)。我不知道它最终是如何解决的,我应该怎么做才能克服这个问题。

来自控制台的错误信息如下。

Exception in thread Thread-1 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.4/threading.py", line 442, in __bootstrap
  File "/opt/company/workspace/username/application/src/mainwidget.py", line 1066, in run
  File "/usr/lib/python2.4/Queue.py", line 89, in put
  File "/usr/lib/python2.4/threading.py", line 237, in notify
exceptions.TypeError: exceptions must be classes, instances, or strings (deprecated), not NoneType
Unhandled exception in thread started by 
Error in sys.excepthook:

Original exception was:

以下是我的部分代码(线程相关代码已完成,其余部分我提取主要操作)。当我使用 GUI 启动外部子进程时,同时创建了一个 wx.TextCtrl 对象。这个 wx.TextCtrl 对象用于提供外部子进程的输入和打印输出

class BashProcessThread(threading.Thread):
    def __init__(self, readlineFunc):
        threading.Thread.__init__(self)
        self.readlineFunc = readlineFunc
        self.lines = []
        self.outputQueue = Queue.Queue()
        self.setDaemon(True)

    def run(self):
        while True:
           line = self.readlineFunc()
           self.outputQueue.put(line)
           if (line==""):
            break
        return ''.join(self.lines)

    def getOutput(self):
        """ called from other thread """            
        while True:
            try:
                line = self.outputQueue.get_nowait()
                lines.append(line)
            except Queue.Empty:
                break
        return ''.join(self.lines)

class ExternalProcWindow(wx.Window):
    def __init__(self, parent, externapp):
        wx.Window.__init__(self, parent, -1, pos=wx.DefaultPosition, size = wx.Size(1200, 120))
        self.externapp=externapp
        self.prompt = externapp.name.lower() + '>>'
        self.textctrl = wx.TextCtrl(self, -1, '', size= wx.Size(1200, 120), style=wx.TE_PROCESS_ENTER|wx.TE_MULTILINE)
        self.default_txt = self.textctrl.GetDefaultStyle()
        self.textctrl.AppendText(self.prompt)
        self.outputThread = BashProcessThread(self.externapp.sub_process.stdout.readline)
        self.outputThread.start()
        self.textctrl.SetFocus()
        self.__bind_events()         
        self.Fit()

    def __bind_events(self):
        self.Bind(wx.EVT_TEXT_ENTER, self.__enter)

    def __enter(self, e):
        nl=self.textctrl.GetNumberOfLines()
        ln =  self.textctrl.GetLineText(nl-1)
        ln = ln[len(self.prompt):]     
        self.externapp.sub_process.stdin.write(ln+"\n")
        time.sleep(.3)
        self.textctrl.AppendText(self.outputThread.getOutput())

class ExternApp:
    def launch(self):
        self.sub_process = subprocess.Popen(launchcmd, stdin=subprocess.PIPE, 
                stdout=subprocess.PIPE, stderr=subprocess.PIPE)

【问题讨论】:

    标签: python multithreading exception wxpython


    【解决方案1】:

    问题是使用threading.Thread.setDaemon引起的。设置守护进程的线程不会阻止 Python 解释器退出,但它们仍会继续运行。因为 Python 在进程终止之前清理了环境,所以当从它们下面删除东西时,线程可能会遇到麻烦。这会引发一个异常,线程类会为了您的方便而尝试打印该异常——但是,由于进程正在退出,该异常也会失败。

    您可以尝试使异常静音,但这很棘手(如果线程做了任何实质性的事情,它可能会隐藏一个真正的问题。但这里不是这种情况。)或者您可以要求线程在 之前停止 退出,并且没有设置线程守护进程。或者您可以完全避免使用线程。我不记得 wxPython 是否有一种方便的机制来获取进程的输出,甚至可以进行异步 I/O,但许多 GUI 工具包都有。并且总有 Twisted,它为你做这一切。

    【讨论】:

    • 嗨,托马斯,谢谢您的回答。我也试过不使用线程,但我不知道怎么做。如何在python中的进程退出之前停止非守护线程?还如何在不更改 theadiing.py 的情况下使异常静音
    • 通常,您使用Queue.Queues 或threading.Event 对象在线程之间进行通信。例如,您可以使用一个事件来告诉线程停止读取行。在这种情况下,您也可以只检查 readline 函数的返回值;如果它返回“”,则您开始的进程退出,线程应该停止。然后,您可以通过终止正在读取输出的进程来结束线程。
    • 嗨,Thomas,当我关闭程序时,我覆盖了 OnClose 函数(首先终止外部进程,然后调用 self.destroy() 关闭主窗口)。不幸的是,外部进程一直在运行,直到我终止它。那么如何停止线程呢?在python中,我没有发现任何函数可以直接终止线程。还有为什么有时会出现这个错误,有时没有错误?
    • 不能从线程外终止线程。你所能做的就是让它退出。例如,使用我已经描述过的一种机制(并且在 readline 函数返回 '' 时让线程停止是一个好主意。)您有时只会看到错误,因为线程不可靠且难以控制;它们在他们想要的时候运行,并且只有有时一个线程想要在它看到的环境的破坏和进程的实际终止之间精确地运行。早一点或晚一点,你看不到任何不好的东西(但它仍然存在。)
    • 非常感谢,Thomas,让我先点击一下,因为您的回答很有用。我在我的代码中尝试了您的好主意“当 readline 函数返回时线程退出”(请参阅​​ BashProcessThread.run(self) 函数中的修订)。是你的意思吗?我会测试它。还是如果外部运行程序stdout"",那是不是虚惊一场?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多