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