Is there a graceful or Pythonic way to interrupt a time.sleep() call in a thread?

multithreading, python

Solution

I am not sure how Pythonic it is but it works. Just use a queue and use blocking get with a timeout. See the example below:

import threading
import Queue
import time

q = Queue.Queue()


def workit():
    for i in range(10):
        try:
            q.get(timeout=1)
            print '%s: Was interrupted' % time.time()
            break
        except Queue.Empty:
            print '%s: One second passed' % time.time()


th = threading.Thread(target=workit)
th.start()

time.sleep(3.2)
q.put(None)

Problem

The code below works the way I expect it to work, namely: - there is a QThread ("Ernie") that counts from 1 to 8, sleeping for 1 second between counts - there is a gratuitous UI widget ("Bert") - under normal operation, the program runs until both the thread finishes and the UI is closed - a Ctrl-C keyboard interrupt will stop the program gracefully prior to normal completion. To do this, I had to break up the 1-second sleep into 50 millisecond chunks that check a flag. Is there a more Pythonic way to sleep in a thread for some amount of time (e.g. 1 second) but be interruptable by some flag or signal? ``` try: for i in xrange(8): print "i=%d" % i for _ in xrange(20): time.sleep(0.05) if not self.running: raise GracefulShutdown except GracefulShutdown: print "ernie exiting" ``` I'd rather do this, and somehow cause a GracefulShutdown exception in the thread: ``` try: for i in xrange(8): print "i=%d" % i time.sleep(1) # somehow allow another thread to raise GracefulShutdown # during the sleep() call except GracefulShutdown: print "ernie exiting" ``` full program; ``` from PySide import QtCore, QtGui from PySide.QtGui import QApplication import sys import signal import time class GracefulShutdown(Exception): pass class Ernie(QtCore.QThread): def __init__(self): super(Ernie, self).__init__() self.running = True def run(self): try: for i in xrange(8): print "i=%d" % i for _ in xrange(20): time.sleep(0.05) if not self.running: raise GracefulShutdown except GracefulShutdown: print "ernie exiting" def shutdown(self): print "ernie received request to shutdown" self.running = False class Bert(object): def __init__(self, argv): self.app = QApplication(argv) self.app.quitOnLastWindowClosed = False def show(self): widg = QtGui.QWidget() widg.resize(250, 150) widg.setWindowTitle('Simple') widg.show() self.widg = widg return widg def shutdown(self): print "bert exiting" self.widg.close() def start(self): # return control to the Python interpreter briefly every 100 msec timer = QtCore.QTimer() timer.start(100) timer.timeout.connect(lambda: None) return self.app.exec_() def handleInterrupts(*actors): def handler(sig, frame): print "caught interrupt" for actor in actors: actor.shutdown() signal.signal(signal.SIGINT, handler) bert = Bert(sys.argv) gratuitousWidget = bert.show() ernie = Ernie() ernie.start() handleInterrupts(bert, ernie) retval = bert.start() print "bert finished" while not ernie.wait(100): # return control to the Python interpreter briefly every 100 msec pass print "ernie finished" sys.exit(retval) ```

Original source

Related problems