我这次用到线程是因为用wxpython做一个界面,通过点击界面的‘运行’,会调用一个线程,并传递一些参数进去,使之运行,但是也有一个“停止”的按钮,如果点击停止,应该让线程结束,但是界面作为主线程,无法安全正常地退出线程,所以只能采用底层接口的东东进行结束这个线程。
注:我为什么没有用子进程subprocess.Popen,是因为我要传递一些对象参数,相当于主线程和子线程同用一些资源,进程就不是这样了,进程间的资源是互相分开的,互不干扰,所以没办法用子进程来传递对象参数,所以只能用线程。
下面这个是线程结束函数,参数是线程pid和执行参数。这里是要让线程退出,所以执行参数是"SystemExit"
def _async_raise(tid, exctype):
'''Raises an exception in the threads with id tid'''
if not inspect.isclass(exctype):
raise TypeError("Only types can be raised (not instances)")
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
ctypes.py_object(exctype))
print 'res:'+str(res)
if res == 0:
raise ValueError("invalid 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")
接下来这个函数是获取线程pid的函数,参数thd是threading.Thread的对象句柄
def __get_my_tid(thd):
"""determines this (self's) thread id
CAREFUL : this function is executed in the context of the caller
thread, to get the identity of the thread represented by this
instance.
"""
if not thd.isAlive():
raise threading.ThreadError("the thread is not active")
# do we have it cached?
if hasattr(thd, "_thread_id"):
return thd._thread_id
# no, look for it in the _active dict
for tid, tobj in threading._active.items():
if tobj is thd:
thd._thread_id = tid
return tid
# TODO: in python 2.6, there's a simpler way to do : self.ident
raise AssertionError("could not determine the thread's id")
这个是使用方法,st为线程句柄,__get_my_tid(st)获取pid, _async_raise(__get_my_tid(st),SystemExit)来强制杀死线程
st = threading.Thread()
_async_raise(__get_my_tid(st),SystemExit)
总结:
官方是没有直接杀死线程的函数的,是因为杀死线程本身可能会带来很多问题,但是对于自己能掌控的还是希望能杀死,这个方法并不见得能成功杀死线程,但是对于一般的还是可以的,千万不能作为万能的啊!