0

I have a problem in managing a infinite while loop in Python, in which I would insert a timer as a sort of "watchdog". I try to explain better: the script has to listen on a serial channel and wait for messages coming from sensors connected on the other side of the channel. I do this with a while True loop because the script must catch all the signals that are passing. However, even if it's probably unnecessary, i would like to insert a timer which is always reset every loop. So, if (for example) the loop get stuck for some reason, the timer will end and will exit the program. I thought i could do this in this way:

def periodicUpdate():
    exitTimer = threading.Timer(60.0, sys.exit())
    while True:
        exitTimer.start()
        readData()
        exitTimer.cancel()

Now, the problem is that when i start the script it immediatly exit. It seems that it reads sys.exit() before all the rest, and it doesn't respect the construct of the timer, but simply when periodicUpdate is called it exits. Why this happen?! I tried changing the syntax, putting sys.exit in an other function and call that function, i tried other solutions but always it behave in two ways: it exits or it behave as the timer doesn't exists. Can someone help me? Thanks very much

kirelagin
  • 13,248
  • 2
  • 42
  • 57
Arbok
  • 63
  • 1
  • 8

8 Answers8

2

It seems that it reads sys.exit() before all the rest

Sure it does. The second argument of threadint.Timer is a function that will be called. What you do is you actually call sys.exit and supply its return value (which is undefined, by the way, since the call terminates the program) as a function to be called. That's an error, since sys.exit's return value is not a function, but that doesn't matter, as the program is terminated anyway.

What you want to do is

exitTimer = threading.Timer(60.0, sys.exit) # note: no brackets

But that actually will not work, as sys.exit in the thread will terminate only that thread. In short, you can't use a watchdog to terminate a stuck while-loop if this loops is in your main thread. In your particular situation you should investigate the function you are using to read data, most likely it lets you set a read timeout.

Community
  • 1
  • 1
kirelagin
  • 13,248
  • 2
  • 42
  • 57
  • Thanks for answer. I tried as you said but withouth the brackets the script seimply behave as the timer doesn't exists. It doesn't exit. It continues to iterate! – Arbok Jun 07 '13 at 09:33
  • @SaiT Oh, sure, `sys.exit` doesn't work from threads, I totally forgot about it. I'll update my answer. – kirelagin Jun 07 '13 at 09:56
  • Thanks for updating :) i'll try to investigate and then i will update you again – Arbok Jun 07 '13 at 12:26
2

Remove the parentheses. If you use sys.exit(), it will fire straight away. When you use sys.exit, it will pass the function as Timer's second argument.

bwind
  • 705
  • 5
  • 7
  • The same as above :) Thanks for answer. But withouth the brackets the script simply behave as the timer doesn't exists. It doesn't exit. It continues to iterate! – Arbok Jun 07 '13 at 09:35
2

I think your approach is not the best one, instead of running a timer that exits the application, why not simply timeout the function that reads the data:

Timeout on a function call

Community
  • 1
  • 1
Samy Arous
  • 6,794
  • 13
  • 20
1

It seems to me that none of the solutions proposed here actually works. This is an example of code. Would be great to know how to fix it. Also, please try it before answering.

import time, threading, sys

def _exit():
    print 'exiting'
    sys.exit()

def periodicUpdate():
    exitTimer = threading.Timer(2.0, _exit)
    while True:
        exitTimer.start()
        print 'go'
        time.sleep(5)
        exitTimer.cancel()


periodicUpdate()

The actual output is:

$python test.py
go
exiting
RuntimeError: threads can only be started once
Fabrizio
  • 437
  • 3
  • 14
0
exitTimer = threading.Timer(60.0, sys.exit)
Armali
  • 18,255
  • 14
  • 57
  • 171
0

Remove the () from sys.exit in timer call

def _exit()
    sys.exit()

def periodicUpdate():
    exitTimer = threading.Timer(60.0, _exit)
    while True:
        exitTimer.start()
        readData()
        exitTimer.cancel()

In you put the () the interpreter call this function if not the interpreter get a reference for this function.

Have fun :)

Edit: Use of _exit

Nasgar
  • 859
  • 2
  • 11
  • 26
  • Hi, and thanks for help! The problem is that if i delete the brackets, the script simply behave as the timer doesn't exists. It doesn't exit... – Arbok Jun 07 '13 at 09:36
  • while trying i get : RuntimeError: threads can only be started once. May you need to create a new timer every loop? – Nasgar Jun 07 '13 at 09:55
  • Honestly i don't get any error! My timer simply doesn't start :D the loop continues to iterate...:S – Arbok Jun 07 '13 at 12:27
0
threading.Timer(60.0, os._exit, [0])
falsetru
  • 357,413
  • 63
  • 732
  • 636
-2
def periodicUpdate():
    exitTimer = sys.exit(60.0, sys.exit())
    while sys.exit():
        sys.exit()
        readData()
        sys.exit()

if __name__ == "__main__":
    sys.exit()

Don't forget to import sys.

gukoff
  • 2,112
  • 3
  • 18
  • 30