Python - do something until keypress or timeout
You can use thread.interrupt_main()
.
Example:
import threadimport timeimport threadinge = threading.Event()def main(): thread.start_new_thread(wait_for_input, tuple()) thread.start_new_thread(do_something, tuple())def wait_for_input(): raw_input() e.set()def do_something(): T0 = time.clock() while (time.clock() - T0) < 60 and not e.isSet(): #as long as 60s haven't elapsed #and the flag is not set #here do a bunch of stuff time.sleep(5) thread.interrupt_main() # kill the raw_input threadtry: thread.start_new_thread(main, tuple()) while 1: time.sleep(0.1) except KeyboardInterrupt: pass
Here is how I solved the issue. I didn't really want to move over to the lower-level thread
module, and I decided I was happy for the user to use CTRL-C to cause the programme to exit gracefully.
It's a bit of a bodge because of the way it repurposes KeyboardInterrupt
, which means it can't really be embedded in code that does need CTRL-C to be an ungraceful exit. However it's OK for my purposes.
import timeimport threadingdef do_something(): T0 = time.clock() while (time.clock() - T0) < 60 and not e.isSet(): #as long as 60s haven't elapsed #and the flag is not set #here do a bunch of stuff time.sleep(5)thread = threading.Thread(target=do_something, args=())e = threading.Event()thread.start()print 'Press CTRL-C to interrupt'while thread.isAlive(): try: time.sleep(1) #wait 1 second, then go back and ask if thread is still alive except KeyboardInterrupt: #if ctrl-C is pressed within that second, #catch the KeyboardInterrupt exception e.set() #set the flag that will kill the thread when it has finished print 'Exiting...' thread.join() #wait for the thread to finish
Update: It actually turned out to be much more straightforward to use a GUI button. The below code doesn't involve the slightly patchy repurposing of KeyboardInterrupt
.
import timeimport threadingimport Tkinter as Tkdef do_something(): T0 = time.clock() while (time.clock() - T0) < 60 and not e.isSet(): #as long as 60s haven't elapsed #and the flag is not set #here do a bunch of stuff time.sleep(5)def _quit(): print 'Exiting...' e.set() thread.join() #wait for the thread to finish root.quit() root.destroy()root = Tk.Tk()QuitButton = Tk.Button(master=root, text='Quit', command=_quit) #the quit buttonQuitButton.pack(side=Tk.BOTTOM)thread = threading.Thread(target=do_something, args=())e = threading.Event()thread.start()root.mainloop()
NOTE: I'd written this answer before you mentioned you were using Windows XP, and as such it won't help you—select
only works on sockets under Windows. I think the answer is still useful for others though, so I'll leave it here.
This gets a bit more complicated than I like to write example code for, because I'm sure it will require some debugging, but I might approach the problem this way:
I'd use select
in a loop, waiting on sys.stdin
, with a five-second timeout. Each time it returned, if no input was present, I'd kick off the thread again (perhaps checking to see if the last thread had actually finished running), then continue the loop. If input was present, I'd exit the loop.
When select
indicates input is present, I could either just consider it an interrupt flat-out or read
in the input and evaulate whether or not it constitutes a valid interruption—if not, I could buffer it pending further input to complete an interruption. If it's an interruption, I'd wait on the thread to complete the work.