1

I am trying to build an GUI application with wxPy that perform some long scripted action. I have put the GUI and the script in different threads to prevent blocking. this worked well except after I close the GUI, the thread containing the script remain running.

below is a simplified version of my program(sorry if the code is hard to understand or missing parts, I am terrible at shortening programs)

class Form(wx.Frame):
    ...
    def test(self, evt):
        t2 = threading.Thread(target = self.runTest)
        t2.start()
    def runTest(self):
       result = really_long_script()

def main():
   app = wx.App(False)
   form = form(app)
   app.MainLoop()

t1 = threading.Thread(target = main)
t1.start()

Is there any way I can just kill the thread? right now the script still runs in background when I close the window.

Any help would be greatly appreciated!

Thanks,

John

prgDevelop
  • 1,557
  • 2
  • 15
  • 26
Noteamini
  • 13
  • 2
  • 5
  • 1
    http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python – Joran Beasley Sep 12 '12 at 20:34
  • as I mentioned the script is quite long and there are many of them, so I don't want to periodically checking for end flag if possible. I am hoping there is an easier solution out there. – Noteamini Sep 13 '12 at 12:41
  • Oh sorry, didn't see the 2nd half of the solution. It seem to stop the threads, but currently self.Destroy freezes the application. Hopefully I can work that out. Thanks a lot! – Noteamini Sep 13 '12 at 15:18

2 Answers2

3

If you set the thread to be a daemon thread, it will die with the main thread.

You can do this by adding the line t2.daemon = True before you call start

Edit: Check this example, with the t.daemon = True line the thread dies when you close the frame, if you comment out that t.daemon = True line, the thread stays alive after the frame closes

import wx
import time
from threading import Thread

def print_something_forever(something):
    while True:
        print something
        time.sleep(1)

class Frame(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self,parent)
        self.panel= wx.Panel(self)
        t= Thread(target=print_something_forever,args=("Thread alive!",))
        t.daemon= True
        t.start()
        self.Show()

if __name__ == "__main__":
    app= wx.App(False)
    Frame(None)
    app.MainLoop()
GP89
  • 6,600
  • 4
  • 36
  • 64
  • I set all threads as daemon, but they kept running after i closed the window. thanks for answering so quick thou. – Noteamini Sep 13 '12 at 12:38
  • hm. I just noticed in your example you thread the `main()` function. That doesn't need to be threaded and could be causing problems. Also the mainloop will only exit if all frames have been closed, which will then end the main thread. Are you sure you have no frames lying around (perhaps invisible ones that haven't had .Show called on them?) – GP89 Sep 13 '12 at 14:12
  • I took main out of the thread, but that didn't do anything. I have only 1 frame in the program, so i shouldn't have any invisible frames. however, since I am fairly new to programming, I could be missing something obvious. what is the proper way of closing a frame? Also, When I use Hide(), does it delete the Item? for example: x = wx.Panel(frame, ...) x.Hide() x = wx.Panel(frame, ...) will this be a problem? – Noteamini Sep 13 '12 at 15:26
  • Does the above example work for you? maybe you could build it up from that until you hit your issue. I was just closing it from the gui with the close cross, but if you need to close it from the code you can call `.Close()` or there's a more forceful `.Destroy()`, both are methods of the frame – GP89 Sep 13 '12 at 15:28
  • the above example didn't seem to work, it keeps on printing 'Thread alive!' after I close the window – Noteamini Sep 13 '12 at 15:32
  • I seem to solved it. based on your example, I had to call sys.exit() when closing the frame, and the threads ended as expected. When I call threading.enumerate(), I observe a thread called _MainThread. I suspect the MainThread is still running when frame is closed, causing the daemon thread to stay alive. do you think sys.exit() will cause any problems? it seems to work for now.Thank you very much for all the help! – Noteamini Sep 13 '12 at 20:36
  • That's odd. what wx version (`import wx; wx.version()`) are you using? closing the last frame should cause mainloop to return and the execution should reach the end of the script and end the main thread. `sys.exit(0)` is probably ok, would be nice to get it working as intended however – GP89 Sep 13 '12 at 20:50
  • Odd, The example above works gives the expected behaviour for me on python 2.7.3 wx 2.8.12.1, windows and mac. Do you have to `sys.exit` to get that example working, or in your program? – GP89 Sep 16 '12 at 01:26
  • Making threads daemons is generally not a good solution for this, as the doc says `Note Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event.` – prgDevelop Sep 16 '17 at 09:33
1

Python doesn't support killing/destroying threads, probably because memory leaks, resources loss, etc.

try this "Threadizing class" :D

class Run_Other_Thread(threading.Thread):
      "Raises a child thread \
       I'm busy dying, rather lying - _P0W !"
      def __init__(self,func_name,*args): #Constructor
            self._func=func_name
            self._func_args=args
            threading.Thread.__init__(self)
      def run(self): # Start Dying
            try:
                print("\n** Running New Thread :"+self._func.func_name)
            except:
                print("\n** Running New Thread :"+self._func.__name__)
            self._func(*self._func_args)
      def stop(self):
            print('!! Stopped')
      def __del__(self):#Constructor
            try:
                print('\n  @@ Farewell :'+self._func.func_name)
            except:
                print('\n  @@ Farewell :'+self._func.__name__)

You may run GUI as:(and try closing)

def GUI():
    app= wx.App(False)
    Frame(None)
    app.MainLoop()

if __name__ == '__main__':
      "Tkinter GUI in Thread helps in De-bugging"
      Run_Other_Thread(GUI).start() # Release command window control
  • Brilliant! No more crashing... the guys who wrote the [MainLoopAsThread](http://wiki.wxpython.org/MainLoopAsThread) page should just point here instead. Their code can't actually close without crashing. I'm hoping to use this with [Radek's](http://radekpodgorny.blogspot.cz/2012/12/working-with-wxpython-in-separate-thread.html) approach to messaging from the main thread. – poleguy Jul 19 '15 at 20:56