On Dec 29 2010, 11:31 pm, gervaz <ger...@gmail.com> wrote: > Hi all, I need to stop a threaded (using CTR+C or kill) application if > it runs too much or if I decide to resume the work later. > I come up with the following test implementation but I wanted some > suggestion from you on how I can implement what I need in a better or > more pythonic way. Here the code:
This is a case that .NET (C#) handles better than Python or Java. It is unsafe to terminate an os level thread at an arbitrary point because it may be executing code in a critical section. Both Java and .NET used to provide ways to terminate threads "safely" by raising an asynchronous exception in the thread. Releasing locks (etc) that the thread holds could then be done in a finally section protecting the code. Python doesn't allow you to abort threads. Unfortunately the thread abort exception could also be raised in the finally section - prematurely aborting the lock / resource cleanup. Java handled this by deprecating thread aborting. (Python has never had it I believe.) .NET handled it by changing the semantics of thread aborting - the thread abort exception will never be raised in a finally block. This makes thread aborting safe, although technically you can subvert it by putting all your code in a finally block (you can also catch and cancel the thread abort exception). The standard advice is to use a flag and do manual checking to abort threads. This only works for fine grained operations and *doesn't* work for very coarse grained operations or where there aren't convenient places to check the flag. It's another place where people sometimes have a genuine need/use case yet people will insist on telling them they don't *really* want it... Anyway, although there are ways based on ctypes to abort Python threads it's not really safe. If you google you should find them, hopefully with intelligible caveat emptor warnings... All the best, Michael Foord > > import os > import signal > import time > from threading import Thread, current_thread > from queue import LifoQueue, Empty > > COMMAND = {"STOP": 0, "NORMAL": 1} > THREAD_NUM = 5 > > lq = LifoQueue() > > print("{0}\n".format(os.getpid())) > > class InterceptInterrupt(Exception): > pass > > class Handler: > def __init__(self, queue): > self._queue = queue > def __del__(self): > print("Bye bye!") > def getHandler(self, signum, frame): > print("Interrupt raised!") > for _ in range(THREAD_NUM): > self._queue.put((COMMAND["STOP"], None)) > raise InterceptInterrupt > > h = Handler(lq) > > signal.signal(signal.SIGINT, h.getHandler) > > for i in range(25): > lq.put((COMMAND["NORMAL"], i)) > > def do_work(queue): > while True: > time.sleep(5) > try: > cmd, value = queue.get(block=False) > if cmd == COMMAND["STOP"]: > print("{0}: STOP command > received!".format(current_thread().name)) > break > elif cmd == COMMAND["NORMAL"]: > print(value) > except Empty: > break > > threads = [Thread(target=do_work, args=(lq,)) for _ in > range(THREAD_NUM)] > > for t in threads: > t.start() > > while not lq.empty(): > try: > time.sleep(1) > except (IOError, InterceptInterrupt): > break > > for t in threads: > t.join() > > if lq.empty(): > print("The queue is empty.") > else: > print("The queue is NOT empty. Some additional work has to be > done.") > > Thank you, > Mattia -- http://mail.python.org/mailman/listinfo/python-list