[C++-sig] boost-python callbacks and GIL lock
David A Wagner
David.A.Wagner at jpl.nasa.gov
Tue Jul 10 20:56:16 CEST 2007
I'm building an interface between python and a middleware system (DDS)
with a C++ API where I want to
be able to use event threads in the middleware framework to drive
callback events in python. I.e., the python
app can register a callback handler object with the API to be notified
when messages arrive on a middleware
topic. Using boost-python I was able to get this to work with only a
few hitches, which I'd like to ask about.
First, let me say that boost-python was a HUGE time saver here. Thanks a
ton to those who developed it!
Basically, I defined a callback interface class in C++ with a virtual
callback method:
class UpdateHandler { virtual void update(Message&); }
where Message is my C++ message data class. I used the boost-python
wrappers to export these classes
to Python. E.g.,:
class_<UpdateHandlerWrapper, boost::noncopyable>("UpdateHandler")
.def("update", pure_virtual(&UpdateHandler::update))
;
with the special callback wrapper function
struct UpdateHandlerWrapper : UpdateHandler,
boost::python::wrapper<UpdateHandler> {
void update(const Message& val) {
// Call the virtual function in
python
this->get_override("update")(val);
}}
This all worked great as long as I was using test code that triggered
the callback from within python.
When we tried to use the actual external threads to pump the events, the
program crashed.
I didn't see anything about this in the boost-python documentation, but
I think the problem had to do with
thread re-entrance in python. Specifically, since these event threads
originate outside of python and its thread
management context, extra code is needed in these callback wrappers to
acquire python's Global Interpreter
Lock (GIL) in order to enter python's interpreter context in a
thread-safe manner:
PyGILState_STATE gstate = PyGILState_Ensure();
// Call the virtual function in
python
this->get_override("update")(val);
PyGILState_Release(gstate);
That seemed to do the trick, but I'd like to get some verification that
this was the appropriate thing to do
here. Is this right? It also makes sense that a call originating from
python would already have this
context, but some foreign thread would not.
Thanks
More information about the Cplusplus-sig
mailing list