Peaser
Peaser

Reputation: 575

Python threading script is not starting/working properly

I quickly wrote this example script for stackoverflow so ignore the functionality aspect of it (my version looks alot better than this), but:

from threading import Thread
from msvcrt import getch       #I'm using Windows by the way.
from time import sleep
import sys

def KeyEvent():
    while True:
        key = getch()
        if key.encode('hex') == '03': #^C
            y = raw_input("Are you sure you want to quit? (y/n): ").lower()
            if y == 'y':
                sys.exit(0)
            else: pass

def main():
    t = 0
    while True:
        print "The count is {0}".format(t)
        t +=1
        sleep(1)

if __name__ == "__main__":
    mainthread = Thread(target = main)
    kev = Thread(target = KeyEvent)

    mainthread.daemon = True
    kev.daemon = True

    mainthread.start()
    kev.start()

What this script is supposed to do is run both loops at the same time, one counts up in seconds, while the other checks for ^C. Please don't recommend that I use a different method, because this is an example.

My problem is, that the script just doesn't start. It displays "The count is 0" and exits, but if I comletely omit the .daemon = True parts, the script runs, but it doesn't run sys.exit(0) correctly. How can I make this script run correctly AND exit when prompted?

Upvotes: 0

Views: 15248

Answers (2)

dgg32
dgg32

Reputation: 1447

You have two problems. First is that your program ends too early. Second is that you try to quit the program in your KeyEvent thread.

Your program terminates early because you didn't hold your main thread. Your main thread ends right after your last statement kev.start() and your daemon threads die with it.

You need a mechanism to hold the main thread infinitively (because you expect the user to type "y" to quit.) There are several ways of doing this. One is add

mainthread.join()

to the end of your code.

Second, sys.exit(0) in your KeyEvent thread obviously can not terminate your whole program. Please find your answer in the following post: Why does sys.exit() not exit when called inside a thread in Python?

Upvotes: 0

Collin
Collin

Reputation: 12287

Threads marked as daemon automatically die when every other non-daemon thread is dead. In your case, the main thread dies just after calling start() on your two daemon threads, bringing the python process with it. That anything gets done in your thread is a matter of luck and timing.

sys.exit(0) does not kill threads other than the main thread. You need a way to signal your threads that it's time to stop. One way to do that is through an Event object.

You shouldn't use getch to try to catch Ctrl+C, try using a signal handler instead:

from threading import Thread
from threading import Event
from time import sleep
import signal

stop = Event()

def handler(signum, frame):
    y = raw_input("Are you sure you want to quit? (y/n): ").lower()
    if y == 'y':
        stop.set()

def main():
    t = 0
    while not stop.isSet():
        print "The count is {0}".format(t)
        t +=1
        sleep(1)

if __name__ == "__main__":
    signal.signal(signal.SIGINT, handler)

    mainthread = Thread(target = main)
    mainthread.start()

    while mainthread.is_alive():
        try:
            mainthread.join(timeout = 0.1)
        except IOError:
            pass #Gets thrown when we interrupt the join

Upvotes: 3

Related Questions