此问题之前已经得到解答,我正在尝试在first answer outlined here中实现第二个解决方案(注意:第一个解决方案与我无关,我的线程是从外部库运行服务器而且可以' t被修改以检查标志)
我试图实现与我的情况相对应的最简单的情况。我有一个产生线程的类,该线程应该在外部停止(线程永远不会自然完成,如本例所示)。 注意:/url#
和_async_raise
是对此问题的接受答案的复制/粘贴:
ThreadWithExc
这会产生import threading
import inspect
import ctypes
import time
# https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python
def _async_raise(tid, exctype):
if not inspect.isclass(exctype):
raise TypeError("Only types can be raised (not instances)")
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
raise SystemError("PyThreadState_SetAsyncExc failed")
# https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python
class ThreadWithExc(threading.Thread):
def _get_my_tid(self):
if not self.isAlive():
raise threading.ThreadError("the thread is not active")
if hasattr(self, "_thread_id"):
return self._thread_id
for tid, tobj in threading._active.items():
if tobj is self:
self._thread_id = tid
return tid
raise AssertionError("could not determine the thread's id")
def raiseExc(self, exctype):
_async_raise( self._get_my_tid(), exctype )
def work():
while True:
print('work')
time.sleep(1)
class Server:
def __init__(self):
self.thread = ThreadWithExc(target=work)
def start(self):
self.thread.start()
def stop(self):
_async_raise(self.thread.raiseExc(TypeError))
server = Server()
server.start()
server.stop()
例外。我还尝试了ValueError: invalid thread id
而不是答案的threading.get_ident()
;这给了我另一个ID,但那个也无效。
答案 0 :(得分:1)
我认为您遇到的根本问题是您没有正确调用_async_raise()
并且应该替换该行:
_async_raise(self.thread.raiseExc(TypeError))
<{1>}中的:
Server.stop()
但是,如果你这样做,你将获得self.thread.raiseExc(TypeError)
,因为Exception in thread Thread-1:
函数中没有异常处理程序来处理由{{work()
引发的异常。 1}}。
以下修复并使用自定义Exception子类使事情更加清晰:
raiseExc()
输出:
import threading
import inspect
import ctypes
import time
# https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python
def _async_raise(tid, exctype):
if not inspect.isclass(exctype):
raise TypeError("Only types can be raised (not instances)")
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
raise SystemError("PyThreadState_SetAsyncExc failed")
# https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python
class ThreadWithExc(threading.Thread):
def _get_my_tid(self):
if not self.isAlive():
raise threading.ThreadError("the thread is not active")
if hasattr(self, "_thread_id"):
return self._thread_id
for tid, tobj in threading._active.items():
if tobj is self:
self._thread_id = tid
return tid
raise AssertionError("could not determine the thread's id")
def raiseExc(self, exctype):
_async_raise(self._get_my_tid(), exctype )
def work():
try:
while True:
print('work')
time.sleep(1)
except Server.ThreadStopped:
pass
print('exiting work() function')
class Server:
class ThreadStopped(Exception): pass
def __init__(self):
self.thread = ThreadWithExc(target=work)
def start(self):
self.thread.start()
def stop(self):
# _async_raise(self.thread.raiseExc(TypeError))
self.thread.raiseExc(self.ThreadStopped)
server = Server()
server.start()
server.stop()
答案 1 :(得分:0)
Python 3.6:
self._thread_id = ctypes.c_long(tid)
Python 3.7:
self._thread_id = ctypes.c_ulong(tid)