1

I'm trying this simple thread with a while loop inside. When I'm inside the while loop, Ctrl+C has no effect in stopping my program. Once I go do something else after the while loop, the script stops as intended. What can I do so my script can be gracefully killed both while being in the while loop and after? (Edit: This seems to be a problem exclusive to Windows, iOS and Ubuntu seem to do what I want)

import time, threading


class MainClass(threading.Thread):

    def __init__(self):
        super().__init__()

    def run(self):
        while True:
            time.sleep(1)
            print("Looping")


# Script entry point
if __name__ == '__main__':

    a = MainClass()
    a.daemon = True
    a.start()
    a.join()
agjc
  • 67
  • 6
  • What Python3 version? What OS? If I run your example, it continually prints "Looping" until I hit Ctrl+C. Then it dumps stack (KeyboardInterrupt) and exits. I am runing Python 3.8.9 on MacOS. – Solomon Slow Nov 10 '21 at 23:05
  • Also, What do "stops as intended" and "gracefully killed" mean? Some people might say that dumping stack is not "graceful." – Solomon Slow Nov 10 '21 at 23:08
  • I'm running python 3.7.5 on Windows (inside a virtual env, but outside it does the same thing). For me it just keeps printing "Looping" until I kill it with the task manager, as Ctrl+C does not have any effect at all. By "gracefully" I mean do not leave any zombie threads behind, bit I don't mind dumping the stack, I just want every thread to stop (I will be using some multiprocessing inside this thread, so I want to make sure everything stops dead once I hit Ctrl+C) – agjc Nov 11 '21 at 08:14

1 Answers1

2

This is a known issue, explained in Issue 35935.

A way to solve it is to revert to the default kernel behaviour of SIGINT using signal.signal(signal.SIGINT, signal.SIG_DFL), (solution pointed out by the issue OP). As to why this has to be the case is beyond the scope of my knowledge.

This works on Windows using Python 3.8+.

Implementation:

import time, threading
import signal


class MainClass(threading.Thread):

    def __init__(self):
        super().__init__()

    def run(self):
        while True:
            time.sleep(1)
            print("Looping")


# Script entry point
if __name__ == '__main__':
    a = MainClass()
    a.daemon=True
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    a.start()
    a.join()
Mr.Mike
  • 51
  • 5