Using Pythonnet I'm calling a long-running method on a CLR object from within a Python script. I want to use BeginAllowThreads to allow other threads obtain the GIL as described here: Pythonnet Threading.
However the call to BeginAllowThreads crashes the whole application with a 'no thread state' error. The calling thread is a CLR worker thread and has the GIL, so I believe it should have a thread state.
Here is a summary of the code sequence:
// In the main thread Pythonnet is initialised like this:
public void Initialise()
{
PythonEngine.Initialize();
m_outerScope = Py.CreateScope( "outerscope" )
...
m_mainThreadState = PythonEngine.BeginAllowThreads();
}
...
// A python script is run on a worker thread like this.
// pyObj is a CLR object with methods the script can call, created
// with clrobj.ToPython():
void runScript( string script, PyObject pyObj, string objName)
{
using( Py.GIL() ) {
using( PyScope scope = m_outerScope.NewScope() ) {
try {
scope.Set( objName, pyObj );
scope.Exec( script );
} catch( Exception exc ) {
...
}
}
}
}
...
// Within the Python script we have something like:
objName.SomeMethod( 'message')
...
// The callback method on the CLR object looks like:
public void SomeMethod( string msg )
{
var state = PythonEngine.BeginAllowThreads();
someLongRunningFunction( msg );
PythonEngine.EndAllowThreads( state );
}
But the no-state error occurs when BeginAllowThreads is called. Without the Begin/EndAllowThreads calls the code works fine but other threads block waiting for the GIL.
It seems as if the worker thread has no thread state within the PythonEngine, but it has the GIL. What am I missing here?