[问题] 停止正在执行 3rd party lib 的 thread

楼主: carylorrk (carylorrk)   2014-08-22 10:03:15
程式执行登入时需要在另一个装置做一些认证
在认证完成前原本程式的 UI 可以取消登入
但是此时做认证的 thread block 在一个 3rd party lib 等待认证回应的 function
所以不能用一般在 thread 下 check event 的方式来决定要不要离开
Google 了一下,找到利用 thread-id raise exception 的方式
http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python
shorten:
http://goo.gl/MRRDFA
但是怎么试也无法成功...都是 invalid thread ID
尝试用文中的 walk 找 tid,或是用 threading.current_thread().ident
得到的都是一个很长的数字,也许不是真正的 tid?
所以试着用 system call 的方式
libc = ctypes.cdll.LoadLibrary('libc.so.6')
tid = libc.syscall(186)
的方式来得到 tid
但是丢进去 PyThreadState_SetAsyncExc 里还是 invalid tid...
也就是 return 是 0
请问该如何得到正确的 tid?
或是有其他方式可以 kill thread? (最好是 portable 的)
也顺便问问是否有其他更好的做法可以避免需要 kill thread?
作者: LiloHuang (十年一刻)   2014-08-22 20:45:00
我想先说明,终止线程跟 OS 本身有极高的相关性我印象中目前并无某种方法,或某个内建的 API可以保证的在所有的系统上,终止某个特定线程。至少 Win32 得用 TerminateThread,不同于 pthread我先假设你所使用的作业系统所操作的是 pthread无论是透过 get_ident 或用 ident 都是拿到 pthread_t也就是 pthread_self() 会拿到的内容 (可查源码参照)你拿到的数值会有点大,我猜你的系统应该是 64 bitStackOverflow 那则被打勾的回应是常见的好方法至少这个方式不是真正强制硬砍掉 Thread 运行然而之所以你会拿到 invalid thread ID 的原因是你得改所有用到 PyThreadState_SetAsyncExc 的部分foobar = ctypes.pythonapi.PyThreadState_SetAsyncExcfoobar.argtypes = [ctypes.c_long, ctypes.py_object]res = foobar(tid, ctypes.py_object(exctype))请把原文章中的 _async_raise 前几行,适度修改如上如此一来就应该不会出现 invalid thread ID 的状况原因是在 64 bit 的环境中,得写清楚带进去的资料型态再透过 _async_raise(thr.ident, RuntimeError) 来终止至于是否有更好的做法? 可以开 child process 也是一种可以把伤害摆到另外一个进程,尽管还是会有机率出状况最好的方式是改 3rd party lib 使其 graceful exit :D行有余力还可以顺便 merge 回 master/trunk 之类的 XD其实我也没仔细看所有回应,只是要说 ctypes 在 64bit的环境得多设定 argtypes 或者直接类似该讨论串中某篇直接生出 c_long(tid) 再进行带入的动作...最好的方式就是用 event / mutex 实作 graceful exit或者用一个 atomic variable 来当作 stop flag 之类的毕竟没看到 3rd party lib 的原始码,我只能猜到这 XD至于 Python 还有个 GIL,如果用一些强制力砍掉 thread如果刚好被砍掉的 thread 是持有 GIL 的话,那就有趣了如果是 mission critical 的环境,就得考量更多的细节总之恭喜你有把问题解决囉 :D毕竟提及 child process 只是想避掉 GIL 这个老问题不应该有GIL的问题,诚如我一开始提到这不是强制砍掉它所谓的强制力是指 pthread_kill or TerminateThread然而如果能实作 graceful exit 还是最好的方向就是 :)因为 PyThreadState_SetAsyncExc 是请求触发 exception并不会真的立刻把该 thread 给终止掉,听起来虽然不错然而如果该 thread 不幸卡在一个很久的 blocking I/O或者该 thread 刚好操作某个会卡很久的 C-API就不一定能如同原本预期,顺利的把 thread 给终止掉了毕竟这个的原理是在 PyEval_EvalFrameEx 还没跑 opcode之前进行检查 tstate->async_exc 的值是否有被设定 :D可参考源码了解更多细节http://goo.gl/878eMi 大概如此

Links booklink

Contact Us: admin [ a t ] ucptt.com