I've nearly solved this problem but I think I need a nudge in the right direction.
I want to do something every five seconds until either a certain amount of time has elapsed or the user interrupts it (in which case it finishes that iteration of the loop before finishing).
import time
import threading
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 = threading.Thread(target=do_something, args=())
thread.start()
e = threading.Event()
while thread.isAlive():
#here I want the main thread to wait for a keypress and, if it receives it,
#set the event e, which will cause the thread to finish its work.
I can't work out how to make that last line work. Using raw_input()
inside the loop will block until the user hits enter whether the thread finishes its work or not. Is there another module that will do what I want?
Edit: I am using Windows XP.
In Python 2 use raw_input(): raw_input("Press Enter to continue...") This only waits for the user to press enter though. This should wait for a keypress.
If you add raw_input('Press any key to exit') it will not display any error codes but it will tell you that the program exited with code 0. For example this is my first program.
join() # Will wait for a thread until it finishes its task. You can also provide a timeout parameter in seconds (real numbers accepted) to the join() method.
Introduction to Python Threading Timer. The timer is a subsidiary class present in the python library named “threading”, which is generally utilized to run a code after a specified time period. Python's threading. Timer() starts after the delay specified as an argument within the threading.
You can use thread.interrupt_main()
.
Example:
import thread
import time
import threading
e = 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 thread
try:
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 time
import threading
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 = 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 time
import threading
import Tkinter as Tk
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)
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 button
QuitButton.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With