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 :)
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.
Tags: threads
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 ??
Abdelrahman:
If you change lines 6 and 12 to :
and
which wrap tid as ctypes.c_long, you'll find it works!