pythonsubprocesspython-multithreading

threading.Thread cannot catch a PyCharm "stop" button termination event


I am using Pycharm. When I click the "stop" button, the subprocess.Popen deletes the left over .bat files. But after putting the subprocess.Popen inside a threading.Thread function, the .bat files are no longer deleted.

Here is some example code:

def threads_(title, index):
    #Create and process .Bat
    with open('test'+str(index)+'.bat', "w", encoding='utf-8') as a: a.write('executable_program.py -start_test "'+title+'"')
    p1 = subprocess.Popen('test'+str(index)+'.bat', stdout=subprocess.PIPE, text=True)
    try:
        while p1.poll() is None:
            time.sleep(0.5)
            _output = p1.stdout.readline()

    except KeyboardInterrupt as e:
        #Cleanup on Exit
        print('Closing ...')
        for c in psutil.Process(p1.pid).children(recursive=True): c.kill()
        psutil.Process(p1.pid).kill()
        print('Cleanup Done')
        os.remove('test'+str(index)+'.bat')
        quit()


def start_threads():
    remaining = ['thread_test1', 'thread_test2', 'thread_test3']
    Globals.thread1 = [Globals.thread1.append(None) for index in range(0, 3)]

    for index in range(0, 3):
        Globals.thread1[index] = threading.Thread(name='thread' + str(index), target=threads_, args=(remaining[index], index))
        Globals.thread1[index].start()


start_threads()

How can I make the threading.Thread function delete files when I push PyCharm's "stop" button?

I also cannot use the join() function when starting the threads.

The following code works with a tkinter root.mainloop(), but it only works like 40% of the time. It doesn't always trigger the handler_stop_signals on exit.

def handler_stop_signals(signum, frame):
    print("Hello world")


def main_thread():
    Globals.root = tk.Tk()
    Globals.root.geometry("+{}+{}".format(650, 50))
    Globals.root.geometry("{}x{}".format(200, 200))
    Globals.root.mainloop()


signal.signal(signal.SIGINT, handler_stop_signals)
signal.signal(signal.SIGTERM, handler_stop_signals)

main_thread()

Solution

  • I have put together a global solution that appears to work for all cases (without any occasional fails) ... threading.Threads , subprocess.Popen, including in combination with tkinters root.mainloop() which occasionally overrides any on-exit termination catch.

    main.py

    #main.py
    import os
    import threading
    import tkinter as tk
    
    def listen_Exit():
        os.system("at_exit.py")
    
    def main_thread():
        root = tk.Tk()
        root.title("Main_GUI")
        root.geometry("+{}+{}".format(650, 50))
        root.geometry("{}x{}".format(200, 200))
    
        threading.Thread(name='process1', target=listen_Exit).start()
        try: root.mainloop()
        except: print('manually terminated')
    
    main_thread()
    

    at_exit.py

    
    #at_exit.py
    import win32gui
    import time
    import os
    
    def termination_code():
        print('terminated')
        if os.path.isfile('D:\\GOOD\\Coding\\.Coding_Projects\\test\\thread_0.bat'):
            os.remove('D:\\GOOD\\Coding\\.Coding_Projects\\test\\thread_0.bat')
    
    
    while True:
        try:
            hwnd = win32gui.FindWindow(None, "Main_GUI")
            print('connected')
            break
        except: time.sleep(1)
    
    
    try:
        print('maintaining connection')
        while True:
            if win32gui.IsWindow(hwnd): pass
            else: print("Connection terminated"); break
            time.sleep(1)
        termination_code()
    except:
        termination_code()
    

    This appears to have the capability of running at_exit.py in the background, until the main program (in any way) is terminated ... and then at_exit.py will clean up any leftover files.