2

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.

  • 1
    Where are you able to catch the KeyboardInterrupt? Can you call t.cancel() when you catch it? Could you set a flag to check to see if you should exit rather than invoking another timer instance? – Eric Renouf Apr 16 '15 at 00:21
  • Perhaps make a function with [`atexit`](https://docs.python.org/3/library/atexit.html#atexit.register) that calls `t.cancel()`? – Navith Apr 16 '15 at 00:23
  • `sys.exit()` takes an integer error code. And you can call `t.cancel()`. – Zizouz212 Apr 16 '15 at 00:24
  • I'm not too familiar with ``Timer`` obj, but considering the thread is a ``dameon`` wouldn't it shut down with the rest of the script? – notorious.no Apr 16 '15 at 00:27
  • You say the timer (and thus the script) keeps executing when you call `sys.exit`? `sys.exit` just raises `SystemExit` so if you are also catching `SystemExit` you may have a problem with that handler. The script and the timer should be gone when you call exit. – tdelaney Apr 16 '15 at 00:48
  • The problem with calling t.cancel() is that I have no access to t in main(). Python's Timer class seems weird in that you have to create a new Timer each time the function is called. Shouldn't you just be able to set the thread to execute every 5 seconds and retain a reference to the thread in the function that called it? Instead of recursively, as shown above. –  Apr 16 '15 at 01:12

4 Answers4

3

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

t.daemon = True

Then sys.exit() should work

brianc
  • 131
  • 1
  • 6
1

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.

MikeOnline
  • 994
  • 11
  • 18
0
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.

notorious.no
  • 4,919
  • 3
  • 20
  • 34
  • How can I call t.cancel() if I have no access to t oustide the function? It seems like based on Python's Timer class you have to set this up recursively and therefore can't access the timer object? –  Apr 16 '15 at 01:18
  • Then create a reference to it outside the function. One thing that comes to mind would be for ``check_buzz()`` to ``return t`` this way you can store it in a global variable and/or pass is to other functions. – notorious.no Apr 16 '15 at 01:35
0

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

Amr El Aswar
  • 3,395
  • 3
  • 23
  • 36