What I'm doing is this:
I have a global variable
PyInterpreterState* my_interp;
The initialization function of my extension module looks like:
void initmymodule(void) {
...
PyEval_InitThreads();
my_interp = PyThreadState_Get()->interp;
}
The callback functions look like:
static void cb_Fun(void* pyFun, T* data)
{
...
// convert data into a Python tuple: arg
ENTER_PY
res = PyEval_CallObject((PyObject*)pyFun, arg);
LEAVE_PY
...
}
where I'm using two macros:
#define ENTER_PY { PyThreadState* tstate = NULL;\
if (_PyThreadState_Current == NULL) {\
tstate = PyThreadState_New(my_interp);\
PyEval_AquireThread(tstate);\
}
#define LEAVE_PY if (tstate) {\
PyThreadState_Clear(tstate);\
PyThreadState_DeleteCurrent();}\
}
The callbacks function can be registered (to a C API) with pyFun
pointing to some Python function (defined in a script). (This Python
function can itself callback into the C API.) In the script, after
registering a function as callback, the main thread is simply looping
in
while running:
time.sleep(0)
Variable `running` can at some point be reset by the callback to break
out of the loop.
The problem is that I still get Fatal Python Errors, like
"PyThreadState_Get: no current thread", and sometimes "ceval: tstate
mix-up".
How is this possible? And how can I prevent those errors? What am I
missing?
(I'm working with Python 2.2 on a Win2000 OS.)
Hans
> I'm writing a Python extension module that has to handle asynchronous
> callbacks.
thats exactly what i did today! i found this aricle very useful:
http://www.linuxjournal.com/article.php?sid=3641
unfortunately (for you) i don't have the sources at hand right now they're
on a powered down machine 3km away and it's raining.... ;-)
>There have been some earlier posts about this, but so far
> I haven't found a safe solution.
>
> What I'm doing is this:
>
> I have a global variable
>
> PyInterpreterState* my_interp;
>
> The initialization function of my extension module looks like:
>
> void initmymodule(void) {
>
> ...
>
> PyEval_InitThreads();
> my_interp = PyThreadState_Get()->interp;
> }
i did this in the function where i register the callback. i also create my
PyThreadState here
--- from the article above
PyThreadState * mainThreadState = NULL;
// save a pointer to the main PyThreadState object
mainThreadState = PyThreadState_Get();
// get a reference to the PyInterpreterState
PyInterpreterState * mainInterpreterState = mainThreadState->interp;
// create a thread state object for this thread
PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
----
i'm holding myThreadState in a global variable.
> The callback functions look like:
>
> static void cb_Fun(void* pyFun, T* data)
> {
> ...
> // convert data into a Python tuple: arg
>
> ENTER_PY
> res = PyEval_CallObject((PyObject*)pyFun, arg);
> LEAVE_PY
> ...
> }
>
> where I'm using two macros:
>
> #define ENTER_PY { PyThreadState* tstate = NULL;\
> if (_PyThreadState_Current == NULL) {\
> tstate = PyThreadState_New(my_interp);\
> PyEval_AquireThread(tstate);\
> }
>
> #define LEAVE_PY if (tstate) {\
> PyThreadState_Clear(tstate);\
> PyThreadState_DeleteCurrent();}\
> }
you should aquire the GIL with PyEval_AcquireLock() and do
PyEval_ReleaseLock() after interacting with python:
---- quote from the article above:
// grab the global interpreter lock
PyEval_AcquireLock();
// swap in my thread state
PyThreadState_Swap(myThreadState);
// execute some python code
PyEval_SimpleString("import sys
");
PyEval_SimpleString("sys.stdout.write('Hello from a C thread!
')
");
// clear the thread state
PyThreadState_Swap(NULL);
// release our hold on the global interpreter
PyEval_ReleaseLock();
----
> The callbacks function can be registered (to a C API) with pyFun
> pointing to some Python function (defined in a script). (This Python
> function can itself callback into the C API.) In the script, after
> registering a function as callback, the main thread is simply looping
> in
>
> while running:
> time.sleep(0)
>
> Variable `running` can at some point be reset by the callback to break
> out of the loop.
>
> The problem is that I still get Fatal Python Errors, like
> "PyThreadState_Get: no current thread", and sometimes "ceval: tstate
> mix-up".
> How is this possible? And how can I prevent those errors? What am I
> missing?
> (I'm working with Python 2.2 on a Win2000 OS.)
>
> Hans
HTH chris
--
Chris <clie...@gmx.net>
>I'm writing a Python extension module that has to handle asynchronous
>callbacks. There have been some earlier posts about this, but so far
>I haven't found a safe solution.
omniORBpy has to do exactly this. When I first wrote it, I created a
new Python thread state on every call, but I discovered that that
imposes a huge overhead. I implemented a cache of thread states, which
halved the invocation time.
The code is in C++, but reading it might help you figure out something
useful to you. Look at pyThreadCache.h and pyThreadCache.cc in this
CVS directory:
Cheers,
Duncan.
--
-- Duncan Grisby --
-- dun...@grisby.org --
-- http://www.grisby.org --