thread.interrupt_main() doesn't work when waiting for input - python

I've read about this technique to timeout blocking IO operations, the problem is that it doesn't seem to work. for example:
import thread, threading
def read_timeout(prompt, timeout=10.0):
timer = threading.Timer(timeout, thread.interrupt_main)
s = ''
timer.start()
try:
s = raw_input(prompt)
except KeyboardInterrupt:
print 'operation timed out.'
timer.cancel()
return s
s = read_timeout('enter input: ')
if s:
print 'you entered: %s' % s
this won't interrupt the main thread until raw_input() returns.
Any help is appreciated.
Update:
Using os.kill(os.getpid(), signal.SIGINT) instead of thread.interrupt_main() seems to work (at least on Linux, which doesn't give me the portability I initially wanted). However, I'm still wondering why the code above doesn't work.

On Unix machines, there is a way to do what you are trying to do. Look at this post:
raw_input and timeout
Just remove the comma at the end of line 5, or the prompt won't be displayed until the program is terminated.
On the same page there's also solution for Windows OS, but I haven't tested it to know if it's working.

According to the latest doc of the API: https://docs.python.org/3/library/_thread.html#thread.interrupt_main
This does not emit the corresponding signal but schedules a call to the associated handler (if it exists).
And the call is performed after the current blocking call in the main thread.
On the contrary, the os.kill solution mentioned in the update actually emits a signal to the main thread.
Sorry that it's been quite a while since the question was raised, but hopefully it still helps.

Related

Is there a way to break out of the time.sleep() method? [duplicate]

I need to break from time.sleep() using ctrl c.
While 1:
time.sleep(60)
In the above code when the control enters time.sleep function an entire 60 seconds needs to elapsed for python to handled the CTRL C
Is there any elegant way to do it. such that I can interrupt even when the control is in time.sleep function
edit
I was testing it on a legacy implementation which uses python 2.2 on windows 2000 which caused all the trouble . If I had used a higher version of python CTRL C would have interrupted the sleep() . I did a quick hack by calling sleep(1) inside a for loop . which temporarily fixed my issue
The correct answer is to use python stdlib's threading.Event
Sure you can tune down your sleep interval so you sleep for very short periods, but what if you actually want to run your loop once every 60s? Then you need to do more work to determine if it's time to run or just keep sleeping. Furthermore, you're still technically blocking but for only a short period of time. Contrast to threading.Event:
from threading import Event
exit = Event()
def main():
while not exit.is_set():
do_my_thing()
exit.wait(60)
print("All done!")
# perform any cleanup here
def quit(signo, _frame):
print("Interrupted by %d, shutting down" % signo)
exit.set()
if __name__ == '__main__':
import signal
for sig in ('TERM', 'HUP', 'INT'):
signal.signal(getattr(signal, 'SIG'+sig), quit);
main()
When the signal handler calls exit.set(), the main thread's wait() call will immediately be interrupted.
Now, you could use an Event to signal that there's more work to do, etc. But in this case it does double duty as a convenient indicator that we want to quit (e.g. the while not exit.is_set() part.)
You also have the option to put any cleanup code after your while loop.
Not sure what the sense of this code is - but if necessary use a shorter sleep() interval and put a for loop around it:
for i in range(60):
sleep(1)
Catching the KeyboardInterrupt exception using try..except is straight-forward
The KeyboardInterrupt exception is raised when a user hits the interrupt key, Ctrl-C. In python this is translated from a SIGINT signal. That means, you can get handle it however you want using the signal module:
import signal
def handler(signum, frame):
print("do whatever, like call thread.interrupt_main()")
signal.signal(signal.SIGINT, handler)
print("Waiting for SIGINT...")
signal.pause()
That way, you can do whatever you want at the receipt of a keyboard interrupt.
The most elegant solution is certainly threading.Event, though if you only need a quick hack, this code works well :
import time
def main():
print("It’s time !")
if __name__ == "__main__":
print("press ctrl-c to stop")
loop_forever = True
while loop_forever:
main()
try:
time.sleep(60)
except KeyboardInterrupt:
loop_forever = False
I tried your code with python versions 2.5, 2.6, 3 under Linux and all throw "KeyboardInterrupt" exception when hitting CTRL-C.
Maybe some exception handling catches the Interrupt or your problem is like this:
Why is KeyboardInterrupt not working in python?
Based on #Andreas Jung answer
for i in range(360):
try:
sleep(1)
except KeyboardInterrupt:
sys.exit(0)
Figured I'd throw this in.
import time
def sleep(seconds):
for i in range(seconds):
try:
time.sleep(1)
except KeyboardInterrupt:
print("Oh! You have sent a Keyboard Interrupt to me.\nBye, Bye")
break
sleep(60)

Is there a way to implement a program termination protocol?

In my case, I am handling databases throughout the entire runtime of my program, and so I need to keep my 'cursor' open for the entire program. Is there anyway I can implement a termination protocol, so that when I terminate its execution or an error arises, I am able to run this quick piece of code that simply closes the cursor (I am using python sockets btw).
I would suspect I could do something like this:
if __name__ == "__main__":
Menu()
cursor.close()
However, the only reason that this doesn't work in my case is that Menu is simply starting up threads, and so its execution continues on, returning me back to cursor.close() whilst my program continues to run.
I'm not sure if there is a way to get around this problem.
Yes, you could use the signal library in python to achieve some of this functionality, in particular, capturing program termination as well interrupts to the program like ctrl + c. Example:
# a function to register the signal handlers
# once the program terminates or is halted by an interrupt like ctrl + c it executes the quit_gracefully function
def register_signal_handler():
signal.signal(signal.SIGINT, quit_gracefully)
signal.signal(signal.SIGTERM, quit_gracefully)
return
def quit_gracefully():
# close connections etc.
in case of a different error you could use a try-except block which handles the error and runs the quit_gracefully function in the except.
try:
# some code
except:
quit_gracefully()
EDIT:
this is a good post on signal. How do I capture SIGINT in Python?
You can also use the atexit module: https://docs.python.org/3/library/atexit.html.
Something like this:
import atexit
#atexit.register
def close_cursor():
print("Closing cursor before exiting.")
cursor.close()

What's a good way to detect when a Python program exits or crashes?

I have the following Python program running in a Docker container.
Basically, if the Python process exits gracefully (ex. when I manually stop the container) or if the Python process crashes (while inside some_other_module.do_work()) then I need to do some cleanup and ping my DB telling it that process has exited.
What's the best way to accomplish this? I saw one answer where they did a try catch on main(), but that seems a bit odd.
My code:
def main():
some_other_module.do_work()
if __name__ == '__main__':
main()
I assume that the additional cleanup will be done by a different process, since the main process has likely crashed in a not recoverable way (I understood the question in this way).
The simplest way would be that the main process sets a flag somewhere (maybe creates a file in a specified location, or a column value in a database table; could also include the PID of the main process that sets the flag) when it starts and removes (or un-sets) that same flag if it finishes gracefully.
The cleanup process just needs to check the flag:
if the flag is set but the main process has ended already (the flag could contain the PID of the main process, so the cleanup process uses that to find if the main process is still running or not), then a cleanup is in order.
if the flag is set and the main process is running, then nothing is to be done.
if the flag is not set, then nothing is to be done.
Try-catch on main seems simplest, but doesn't/may not work for most things (please see comments below). You can always except specific exceptions:
def main():
some_other_module.do_work()
if __name__ == '__main__':
try:
main()
except Exception as e:
if e == "<INSERT GRACEFUL INTERRUPT HERE>":
# finished gracefully
else:
print(e)
# crash
Use a try/except
def thing_that_crashes():
exit()
try:
thing_that_crashes()
except:
print('oh and by the way, that thing tried to kill me')
I think it is impossible to catch a process with advanced suicidal behaviour (I don't know sending a SYGKILL to itself or something) so if you need your main process to live whatever happens, maybe run the other one in a subprocess.
You could wrap your script with another subprocess script and check the returncode. Inspired by this Relevant question.
from subprocess import Popen
script = Popen("python abspath/to/your/script.py")
script.communicate()
if script.returncode <> 0:
# something went wrong
# do something about it

Stop pyzmq receiver by KeyboardInterrupt

Following this example in the ØMQ docs, I'm trying to create a simple receiver. The example uses infinite loop. Everything works just fine. However, on MS Windows, when I hit CTRL+C to raise KeyboardInterrupt, the loop does not break. It seems that recv() method somehow ignores the exception. However, I'd love to exit the process by hiting CTRL+C instead of killing it. Is that possible?
In response to the #Cyclone's request, I suggest the following as a possible solution:
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL);
# any pyzmq-related code, such as `reply = socket.recv()`
A zmq.Poller object seems to help:
def poll_socket(socket, timetick = 100):
poller = zmq.Poller()
poller.register(socket, zmq.POLLIN)
# wait up to 100msec
try:
while True:
obj = dict(poller.poll(timetick))
if socket in obj and obj[socket] == zmq.POLLIN:
yield socket.recv()
except KeyboardInterrupt:
pass
# Escape while loop if there's a keyboard interrupt.
Then you can do things like:
for message in poll_socket(socket):
handle_message(message)
and the for-loop will automatically terminate on Ctrl-C. It looks like the translation from Ctrl-C to a Python KeyboardInterrupt only happens when the interpreter is active and Python has not yielded control to low-level C code; the pyzmq recv() call apparently blocks while in low-level C code, so Python never gets a chance to issue the KeyboardInterrupt. But if you use zmq.Poller then it will stop at a timeout and give the interpreter a chance to issue the KeyboardInterrupt after the timeout is complete.
Don't know if this going to work in Windows, but in Linux I did something like this:
if signal.signal(signal.SIGINT, signal.SIG_DFL):
sys.exit()
Try ctrl+break (as in the key above Page Up, I had to look it up, I don't think I've ever touched that key before)
suggested near the bottom of this thread. I haven't done anything too fancy, but this seems to work well enough in the cases I've tried.

Using a timer in a while true loop in Python

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
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.
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
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.
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
exitTimer = threading.Timer(60.0, sys.exit)
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
threading.Timer(60.0, os._exit, [0])
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.

Categories

Resources