user2563044
user2563044

Reputation:

Python: Timer, how to stop thread when program ends?

I have a function I'm calling every 5 seconds like such:

def check_buzz(super_buzz_words):
    print 'Checking buzz'
    t = Timer(5.0, check_buzz, args=(super_buzz_words,))
    t.dameon = True
    t.start()
    buzz_word = get_buzz_word()
    if buzz_word is not 'fail':
        super_buzz_words.put(buzz_word)

main()
 check_buzz()

I'm exiting the script by either catching a KeyboardInterrupt or by catching a System exit and calling this:

sys.exit('\nShutting Down\n')

I'm also restarting the program every so often by calling:

execv(sys.executable, [sys.executable] + sys.argv)

My question is, how do I get that timer thread to shut off? If I keyboard interrupt, the timer keeps going.

Upvotes: 2

Views: 3123

Answers (4)

MikeOnline
MikeOnline

Reputation: 1204

Expanding on the answer from notorious.no, and the comment asking:

How can I call t.cancel() if I have no access to t oustide the function?

Give the Timer thread a distinct name when you first create it:

import threading

def check_buzz(super_buzz_words):
    print 'Checking buzz'
    t = Timer(5.0, check_buzz, args=(super_buzz_words,))
    t.daemon = True
    t.name = "check_buzz_daemon"
    t.start()

Although the local variable t soon goes out of scope, the Timer thread that t pointed to still exists and still retains the name assigned to it.

Your atexit-registered method can then identify this thread by its name and cancel it:

from atexit import register

def all_done():
    for thr in threading._enumerate():
        if thr.name == "check_buzz_daemon":
            if thr.is_alive():
                thr.cancel()
                thr.join()

register(all_done)

Calling join() after calling cancel()is based on a StackOverflow answer by Cédric Julien.

HOWEVER, your thread is set to be a Daemon. According to this StackOverflow post, daemon threads do not need to be explicitly terminated.

Upvotes: 1

brianc
brianc

Reputation: 151

I think you just spelled daemon wrong, it should have been:

t.daemon = True

Then sys.exit() should work

Upvotes: 3

Amr El Aswar
Amr El Aswar

Reputation: 3515

Another way would be to use the Queue() module to send and recieve info from a thread using the .put() outside the thread and the .get() inside the thread. What you can also do is create a txt file and make program write to it when you exit And put an if statement in the thread function to check it after each iteration (this is not a really good solution but it also works) I would have put a code exemple but i am writing from mobile sorry

Upvotes: 0

notorious.no
notorious.no

Reputation: 5107

from atexit import register

def all_done():
    if t.is_alive():
        # do something that will close your thread gracefully

register(all_done)

Basically when your code is about to exit, it will fire one last function and this is where you will check if your thread is still running. If it is, do something that will either cancel the transaction or otherwise exit gracefully. In general, it's best to let threads finish by themselves, but if it's not doing anything important (please note the emphasis) than you can just do t.cancel(). Design your code so that threads will finish on their own if possible.

Upvotes: 0

Related Questions