OOF2: The Manual
Name
acquirePyLock — ensure thread-safe Python API calls
Synopsis
#include "common/threadstate.h"
void
acquirePyLock
( |
);
|
void
releasePyLock
( |
);
|
#include "common/ooferror.h"
void
pythonErrorRelay
( |
);
|
Description
The three functions described here are used whenever OOF2 C++ code calls Python API functions that might invoke the Python interpreter. It's often difficult to tell when the interpreter will be invoked, so it's a good idea to treat all Python API calls in this way. See http://docs.python.org/ext/thinIce.html for a relevant discussion (although in a different context).
Because the Python interpreter is not thread safe, whenever
a C++ function in OOF2 needs to call the Python API, it
must first acquire the Python global interpreter lock by
calling acquirePyLock(). When it's
through with the Python API calls, it must release the lock
by calling releasePyLock().
A function that neglects to call
acquirePyLock() risks crashing the
Python interpreter. A function that neglects to call
releasePyLock will probably deadlock
the program when the C++ routine finishes. If running
OOF2 with the --unthreaded
option solves a crashing or deadlocking problem, then check
the code for missing calls to
acquirePyLock and
releasePyLock.
It is important to ensure that
releasePyLock is called even if an
exception is thrown during the Python API calls. Python API
calls should always occur within a try
... catch block, like this:
#include "common/threadstate.h"
acquirePyLock();
try {
// Call Python API
}
catch (...) {
releasePyLock();
throw;
}
releasePyLock();
It's possible that calls to the Python API will raise a
Python exception but not throw a C++
exception. Generally, if a Python API function returns
NULL, an exception has been raised. The
OOF2 function pythonErrorRelay
ensures that Python exceptions are re-raised in Python when
the C++ function exits. It should be used like this:
#include "common/ooferror.h"
#include "common/threadstate.h"
acquirePyLock();
try {
PyObject *func, *args; // assume these have been set
PyObject *result = PyEval_Call_Object(func, args); // for example
if(result == NULL)
pythonErrorRelay();
// do something with result
}
catch (...) {
releasePyLock();
throw;
}
releasePyLock();
pythonErrorRelay raises a C++ exception
that will be converted back into a Python exception when
control returns to Python. The mechanism even works if the
Python exception was caused by a C++ exception that occurred
during a second call back into C++, as long as the original
C++ exception was derived from the OOF2 ErrError
class.



