In my application, the main thread in in charge of UI drawing with wxPython and starting worker threads which runs user defined Python code. If a user defined Python code is buggy the application user needs to stop it. There's a way to raise a KeyboardInterrupt exception in the main thread but unfortunately not the opposite. What I needed to do is interrupting a sub thread from the main thread. I don't know why it doesn't exist. Probably it is a well considered decision but what I need is what Python misses. The API provides a function PyThreadState_SetAsyncExc() which takes a thread id and exception object and raises exception in the thread. So I had to make a wrapper extension.
pySubthreadInterruptTest.c
#include <Python.h> static PyObject* interrupt(PyObject* self, PyObject* args) { long threadid; PyObject* po_exception; if(! PyArg_ParseTuple(args, "lO", &threadid, &po_exception)) { return NULL; } int result = PyThreadState_SetAsyncExc(threadid, po_exception); return Py_BuildValue("l", result); } static PyMethodDef MethodsDefs[] = { {"interrupt", interrupt, METH_VARARGS}, {NULL, NULL, 0}, }; void initpystit(void){ (void) Py_InitModule("pystit", MethodsDefs); }
setup.py
from distutils.core import setup, Extension module1 = Extension('pystit', sources = ['pySubthreadInterruptTest.c']) setup (name = 'PackageName', version = '1.0', description = 'This is a demo package', ext_modules = [module1])
test.py
import time, thread import pystit def f(): print 'thread start' try: for i in range(1000): print i time.sleep(0.001) except: print 'interrupted' raise print 'thread end' tid = thread.start_new_thread(f, ()) time.sleep(0.001) pystit.interrupt(tid, ValueError) time.sleep(1)
$ python setup.py build running build running build_ext building 'pystit' extension gcc -pthread -shared build/temp.linux-i686-2.6/pySubthreadInterruptTest.o -L/usr/lib -lpython2.6 -o build/lib.linux-i686-2.6/pystit.so $ cd build/lib.linux-i686-2.6/ $ ls pystit.so test.py $ python test.py thread start 0 1 2 3 interrupted Unhandled exception in thread started by <function f at 0xb8043e64> Traceback (most recent call last): File "test.py", line 8, in f time.sleep(0.001) ValueError $
It works but I can't say I'm quite satisfied with the solution.
No comments:
Post a Comment