Skip to content

Instantly share code, notes, and snippets.

@Irfy
Last active February 19, 2019 10:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Irfy/1821876 to your computer and use it in GitHub Desktop.
Save Irfy/1821876 to your computer and use it in GitHub Desktop.
Demonstrates a way to run blocking functions which require Ctrl-C handling capability on the main thread via queues from other threads in Python
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 during Queue.get
try:
result = fun(*args, **kwargs)
except BaseException, e:
result_queue.put((None, e))
else:
result_queue.put((result, None))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment