public
Last active

Demonstrates a way to run blocking functions which require Ctrl-C handling capability on the main thread via queues from other threads in Python

  • Download Gist
so9269338.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
from Queue import Queue, Empty
from functools import wraps
from threading import Thread, Semaphore
 
ctrlc_queue = Queue()
exit_sem = Semaphore(0) # Read: there are 0 ctrlc threads on start-up
 
def needs_ctrlc(fun):
@wraps(fun)
def wrapped(*args, **kwargs):
result_queue = Queue()
ctrlc_queue.put((fun, args, kwargs, result_queue))
result, exception = result_queue.get()
if exception:
raise exception
return result
return wrapped
 
@needs_ctrlc
def process_input(threadno):
print raw_input("[%d] Write something: " % threadno)
 
def thread_loop(threadno):
exit_sem.release() # Read: add 1 to number of ctrlc threads
try:
for _ in xrange(5):
process_input(threadno)
pass
except KeyboardInterrupt:
pass
print "[%d] Caught KeyboardInterrupt, exiting thread" % threadno
else:
print "[%d] Finished input, exiting thread" % threadno
finally:
exit_sem.acquire() # Read: subtract 1 from number of ctrlc threads
pass
 
def ctrlc_threads_exist():
"""As soon as exit_sem.acquire() blocks, we know there are no mor threads"""
ctrlc_threads_exist = exit_sem.acquire(False)
if ctrlc_threads_exist:
exit_sem.release()
return ctrlc_threads_exist
 
if __name__ == '__main__':
for i in xrange(5):
Thread(target=thread_loop, args=(i,)).start()
# you *may* need to sleep a millisecond or two here
while ctrlc_threads_exist():
try:
fun, args, kwargs, result_queue = ctrlc_queue.get(timeout=1)
except Empty:
continue # must check exit_event regularly
except KeyboardInterrupt:
continue # unintentional Ctrl-C drugin Queue.get
try:
result = fun(*args, **kwargs)
except BaseException, e:
result_queue.put((None, e))
else:
result_queue.put((result, None))

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.