A little module that extends the threading's module functionality -- allows one thread to raise exceptions in the context of another thread. By raising SystemExit, you can finally kill python threads :)
Python, 30 lines
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
import threading import ctypes def _async_raise(tid, excobj): res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj)) if res == 0: raise ValueError("nonexistent thread id") elif res > 1: # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0) raise SystemError("PyThreadState_SetAsyncExc failed") class Thread(threading.Thread): def raise_exc(self, excobj): assert self.isAlive(), "thread must be started" for tid, tobj in threading._active.items(): if tobj is self: _async_raise(tid, excobj) return # the thread was alive when we entered the loop, but was not found # in the dict, hence it must have been already terminated. should we raise # an exception here? silently ignore? def terminate(self): # must raise the SystemExit type, instead of a SystemExit() instance # due to a bug in PyThreadState_SetAsyncExc self.raise_exc(SystemExit)
There are some issues with this code, refer to http://tomerfiliba.com/recipes/Thread2/ for more info and details. Requires ctypes.
Small bug in the recipe. The second call to PyThreadState_SetAsyncEx must use 'None' as second parameter, otherwise it will not work correctly on 64-bit plaforms:
'None' will be passed as pointer parameter, '0' would be passed as integer.
this code is not up-to-date. see the link i gave for the full (updated) recipe
it's easier in python3. in python3 you can just call _stop() on the thread object.
No, ._stop() is unrelated. A thread calls it when it finishes, to mark itself as stopped and wake up anybody who called .wait(). The naming is poor - ._mark_as_stopped() would have been a better choice.
well, for me(using python2.6) on ubuntu 9.10 i always got invalid thread id when testing the script any idea why ??
If you change lines 6 and 12 to :
which wrap tid as ctypes.c_long, you'll find it works!