asynchronous callbacks

Chris Liechti cliechti at gmx.net
Thu May 23 15:35:02 EDT 2002


hans.geuns at scansoft.com (hans) wrote in 
news:dae4590e.0205231025.7cbb29af at posting.google.com:

> 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 <cliechti at gmx.net>




More information about the Python-list mailing list