Problem calling python.Net from a winforms Background worker thread

mskeel

Senior Contributor
Joined
Oct 30, 2003
Messages
913
A colleague and are attempting to add python scripting support to a win forms application developed in .Net 2.0. The initial prototyping went well but the new scripting components stopped working once we integrated it into the main application. We think we've isolated the problem to either a problem with Python.Net, the python implementation we are using, or how we invoke the python scripts from within the background worker thread.

Here is a simplified code snippet that recreates the issue we are seeing:


Code:
PyObject pyPlugin;
string pathToScript;

private void button1_Click(object sender, EventArgs e)
{
   //*************** START SECTION 1 ****************************

   pathToScript = @"C:\Dev\pyScripts\sample.py";
   Environment.SetEnvironmentVariable("PYTHONHOME", Path.GetDirectoryName(pathToScript));

   PythonEngine.Initialize();
   
   string oldWorkingDirectory = Directory.GetCurrentDirectory();
   Directory.SetCurrentDirectory(Path.GetDirectoryName(pathToScript));

   pyPlugin = PythonEngine.ImportModule(Path.GetFileNameWithoutExtension(pathToScript));

   Directory.SetCurrentDirectory(oldWorkingDirectory);
   MessageBox.Show(pyPlugin.GetAttr("foo").Invoke().ToString());

   //*************** END SECTION 1 *****************************

   BackgroundWorker workerThread = [URL="http://www.google.com/search?q=new+msdn.microsoft.com"]new[/URL] BackgroundWorker();
   workerThread.DoWork += workerThreadProcessing;
   workerThread.RunWorkerAsync();
}


public void workerThreadProcessing(object sender, EventArgs e)
{
   pathToScript = @"C:\Dev\pyScripts\sample.py";
   Environment.SetEnvironmentVariable("PYTHONHOME", Path.GetDirectoryName(pathToScript));

   PythonEngine.Initialize();
   string oldWorkingDirectory = Directory.GetCurrentDirectory();
   Directory.SetCurrentDirectory(Path.GetDirectoryName(pathToScript));

   pyPlugin = PythonEngine.ImportModule(Path.GetFileNameWithoutExtension(pathToScript));

   Directory.SetCurrentDirectory(oldWorkingDirectory);
   MessageBox.Show(pyPlugin.GetAttr("bar").Invoke().ToString());

}


As you can see in the code above, I first call the foo method from the main thread. I then invoke a worker thread and in that thread, create a new pyObject and call the bar method from the python script.

The problem occurs on the last line of the workerThreadProcessing. When this line is executed, the application hangs indefinitely. The catch is that if I comment out the contents of "SECTION 1", bar completes as desired. This seems to indicate that there is something in "SECTION 1" that is causing the problem.

The python script, sample.py is trivial:
Code:
def foo():
              return "foo has been called"
              
  def bar():
              return "bar has been called"
We have a similar troubleshooting thread going through the python.net mailing list right now to determine if there is a limitation in python.net but I am concerned that we've missed something important on the .Net side. Are there any known issues with the background worker that might be causing a problem? Have I made some kind of fundamental mistake that I'm just not seeing?

Any help or insight (on either side of this problem) is greatly appreciated.
 
Python and threading

http://pythonnet.sourceforge.net/readme.html#embedding

Before interacting with any of the objects or APIs provided by the Python.Runtime namespace, calling code must have acquired the Python global interpreter lock by calling the PythonEngine.AcquireLock method. The only exception to this rule is the PythonEngine.Initialize method, which may be called at startup without having acquired the GIL.

When finished using Python APIs, managed code must call a corresponding PythonEngine.ReleaseLock to release the GIL and allow other threads to use Python.

And http://www.python.org/doc/2.4/api/threads.html

Good luck :cool:
 
Re: Python and threading

Thanks, MrPaul. Unfortunately, it seems like there might be an issue with the PythonEngine.AcquireLock() method. That method is supposed to return an intPtr, which I assume is to be used later on to release the thread lock by calling PythonEngine.ReleaseLock(intPtr). The problem is that the call to PythonEngine.AcquireLock() is returning zero and the problem persists even if we do things "the right way."

I'm still investigating and will post the solution once we have determined how to get this working.
 
Back
Top