wxPython OnExit()没有停止线程?

时间:2013-03-13 03:55:51

标签: python multithreading wxpython

我正在尝试创建一个线程,并在关闭wxPython应用程序的框架时结束它。这是我的代码:

#! /usr/bin/env python

import time, wx
from threading import Thread

class UpdateThread(Thread):
    def __init__(self):
        self.stopped = False
        Thread.__init__(self)
    def run(self):
        while not self.stopped:
            self.updateExchange()
            time.sleep(1)
    def updateExchange(self):
        print("Updated...")

class tradeWindow(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, "Exchange", size = (500, 190))
        panel = wx.Panel(self)
    def OnExit(self):
        tickThread.stopped # I've also tried: tickThread.stopped = True

tickThread = UpdateThread()
tickThread.start()
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = tradeWindow(parent = None, id = -1)
    frame.Show()
    app.MainLoop()

但当我关闭相框时,它会继续打印。

2 个答案:

答案 0 :(得分:6)

没有魔法Frame.OnExit方法。你正在混合框架和应用程序。框架,像其他窗户一样,关闭。应用退出。

因此,您可以将代码放入app类的OnExit方法中。但这不是你想要的。

查看this simple tutorial OnExit方法。同样,这不是你想要的,但你应该知道它是如何工作的(以及它被调用的对象)。

您始终可以绑定EVT_CLOSE以在窗口中调用您想要的任何内容。但你必须明确地这样做。

通常,您调用方法OnCloseOnCloseWindow。调用它OnExit只会导致严重的混乱(因为它)。

您绑定的事件处理程序方法必须实际上是一个事件处理程序,这意味着它需要一个event参数(以及self)。

接下来,如果添加EVT_CLOSE处理程序,则覆盖默认处理程序,这意味着Destroy永远不会被调用,除非您自己执行。

以下a tutorial绑定EVT_CLOSE,其中显示了上述所有步骤。

最后,正如DavidRobinson所解释的那样,只做tickThread.stopped不会做任何事情;你必须将它设置为True

全部放在一起:

class tradeWindow(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, "Exchange", size = (500, 190))
        panel = wx.Panel(self)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
    def OnClose(self, event):
        tickThread.stopped = True
        self.Destroy()

还有一点需要注意:

在任何严重的线程程序中,如果要在线程之间共享值,通常需要将其与某种同步对象同步。如果您正在等待来自另一个线程的信号,那么处理该信号的典型方法是使用Condition。另一方面,如果您只想分享价值,可以使用Lock

如果您真的知道自己在做什么,通常可以让Global Interpreter Lock为您处理同步。但总的来说,这是一个坏主意。例如,您的主线程可以在核心0上运行,而后台线程可以在核心1上运行,并且Python语言定义中没有任何内容可以保证计算机将更新的值从核心0的缓存复制到核心1。因此,您的后台线程可能会永远旋转,观察旧值并永远不会看到新值。事实证明,在x86上使用CPython 2.0-3.3时,你的代码不可能发生这种情况 - 但是你可以证明(或至少确定安全的情况),不要指望它。


最后,您询问守护程序线程是否是合适的解决方案。来自the docs

  

这个标志的意义在于,当只剩下守护进程线程时,整个Python程序都会退出。

换句话说,您的程序可以在不必停止守护程序线程的情况下退出。但...

  

注意守护程序线程在关闭时突然停止。他们的资源(例如打开文件,数据库事务等)可能无法正确发布。如果您希望线程正常停止,请使它们成为非守护进程并使用合适的信令机制,例如Event

答案 1 :(得分:1)

尝试在tickThread.setDaemon(True)之前设置tickThread.start() - Daemon threads应该以其父线程退出。