Re: Py_NewInterpreter(), is this a bug in the python core?

2006-07-13 Thread freesteel
freesteel wrote:
> Yes, I see that now in the documentation, which to me is quite
> confusing.
> So, how do you use python in a multithreaded environment, where for
> example you want to run some embeded python code from a number of
> different C threads?
>
> This article: http://www.linuxjournal.com/article/3641 is quite good,
> but must have been written before these PyGILState_* functions.
>
> I only used Py_NewInterpreter to have a fresh 'import sys'.
>
> Somebody enlighten me, please.
>
> Martin

If you try to replicate the code from the linux journal
(http://www.linuxjournal.com/article/3641) and compile with Py_DEBUG
defined, when running it you will find that you get an exception and a
fatal error message from the python core. The exception is thrown from
pystate.c, line 306:
Py_FatalError("Invalid thread state for this thread");

The exception is thrown in my understanding of the code because there
can only ever be one thread state. If  this is true a function to swap
thread states seems rather pointless.
Now, reading up about how to call C API to python from a C thread I
find that with version 2.3 the function pair
PyGILState_Ensure/PyGILState_Release was introduced. This allows
'grabbing' the global interpreter lock, calling your embedded python
code and release the GIL at the end again.

Am I right in my understanding that the use of this PyGILState_* pair
is meant to 'replace' the prologue of creating a new thread state from
the main thread state, swapping it with the current state, doing your
Python/C API calls and then in an epilogue swap the previous thread
state back in, and deletie the now obsolete previously created thread
state?

At least that how I understand the motivation behind the introduction
of tPyGILState_*, read here:
http://www.python.org/dev/peps/pep-0311/

Now, I tried to use this mechanism, but I am not really successful with
it. Basically, in my C thread, I wrap a number of calls to embedded
python (a few PyRun_SimpleString calls, nothing really fancy) with
PyGILState_Ensure and PyGILState_Release. The first C thread also
initializes python as well as initializes threading:
Py_Initialize();
PyEval_InitThreads();

(If it helps I can post my whole code here).

When I test this I get deadlocks in most cases after the first thread
has called PyGILState_Release. All other threads at that point 'freeze'
and never return from whatever Python/C API function they are in. I
don't understand why. Moreover, this behavious is not always
reproducable, sometimes the code works as intended. Must be some kind
of race condition? Who can help?

I read that the problem of calling python from a multithreaded
application per thread is very difficult, but a few projects have
managed to solve it, but now we have these PyGILStates and all is much
easier?

Martin

-- 
http://mail.python.org/mailman/listinfo/python-list


embedded python and windows multi threading, can't get it to work

2006-06-13 Thread freesteel
I am trying to run a python programme embedded from C++. I want to run
the same python code concurrently in several threads. I read the manual
on embedding, especially chapter 8, and searched for relevant info on
google all afternoon, but I can't get this to work. What am I doing
wrong? I use python2.4 and vc++7 (.net). The first thread seems to work
okay, the 2nd thread crashes, but the exception information is not very
useful:
(An unhandled exception of type 'System.NullReferenceException'
occurred in pyembed_test.exe

Additional information: Object reference not set to an instance of an
object.)

Here is a simplified example, it is heavily based on this article:
http://www.codeproject.com/cpp/embedpython_1.asp



#include 
#include 
#include 
#include 

#define USE_AFX 0




#if USE_AFX
UINT MyThread(LPVOID lpParam)
#else
void MyThread(void* lpParam)
#endif
{
Py_Initialize();
//#if 0
//  PyEval_InitThreads();
PyThreadState *mainthreadstate = PyThreadState_Get();
PyInterpreterState *maininterpreterstate = mainthreadstate->interp;
PyThreadState *mythreadstate =
PyThreadState_New(maininterpreterstate);
PyEval_ReleaseLock();
PyEval_AcquireLock();
PyThreadState *tmpstate = PyThreadState_Swap(mythreadstate);
//#endif


int* num = (int *)lpParam;
int ret = 0;
ret = PyRun_SimpleString("x = []");
ret = PyRun_SimpleString("for i in range(10):\n  x.append(i)");
char cmd[100];
sprintf(cmd, "f = open('test%d.txt', 'w')", *num);
ret = PyRun_SimpleString(cmd);
ret = PyRun_SimpleString("f.write('%s' % x.__str__())");
ret = PyRun_SimpleString("f.close()");

//#if 0
PyThreadState_Swap(tmpstate);
PyEval_ReleaseLock();
PyThreadState_Clear(mythreadstate);
PyThreadState_Delete(mythreadstate);
//#endif



Py_Finalize();
#if USE_AFX
return 0;
#else
_endthread();
#endif
}

class CMyWinApp : public CWinApp
{
public:
CMyWinApp() { }
BOOL InitInstance()
{
int num0 = 0, num1 = 1;
HANDLE hnd0, hnd1;
#if USE_AFX
CWinThread* pThread0 = AfxBeginThread(MyThread, &num0);
hnd0 = pThread0->m_hThread;
CWinThread* pThread1 = AfxBeginThread(MyThread, &num1);
hnd1 = pThread1->m_hThread;
#else
hnd0 = (HANDLE) _beginthread(MyThread, 0, &num0);
hnd1 = (HANDLE) _beginthread(MyThread, 0, &num1);
#endif

// wait for the worker thread to terminate.
WaitForSingleObject(hnd0, INFINITE);
WaitForSingleObject(hnd1, INFINITE);

return TRUE;
};
};

CMyWinApp app;

-- 
http://mail.python.org/mailman/listinfo/python-list


multithreading windows and embedding python

2006-06-19 Thread freesteel
I have posted about this problem before. SInce then I found a much
better article to help with embedding python in a multithreaded
application:

http://www.linuxjournal.com/article/3641

I found this article very good and it clarified for me what needs
doing. Now I have an example application that almost works, but it is
far from reliable. If I run this several times I get crashes telling me
that the heap is modified after deallocation. Can anybody else
reproduce this?

At the bottom of this file I left a debug dump, and a stack dump.

Here is my application, compile in windows using a standard windows
application project.




#include 
#include 
#include 
#include 
#include 
#include 

static int threadnum = 0;




UINT MyThread(LPVOID lpParam)
{
ASSERT(Py_IsInitialized());
threadnum++;


PyThreadState* mainThreadState = (PyThreadState *)lpParam;

// get the global lock
PyEval_AcquireLock();
// get a reference to the PyInterpreterState
PyInterpreterState * mainInterpreterState = mainThreadState->interp;
PyThreadState_Swap(mainThreadState);

// create a thread state object for this thread
PyThreadState * myThreadState =
PyThreadState_New(mainInterpreterState);
// free the lock
PyEval_ReleaseLock();


// lock - swap in thread state - swap out thread state - unlock
PyEval_AcquireLock();
PyThreadState_Swap(myThreadState);

int num = 0;
int ret = 0;
ret = PyRun_SimpleString("x = []");
ret = PyRun_SimpleString("for i in range(10):\n  x.append(i)");
char cmd[100];
sprintf(cmd, "f = open('c:/windows/temp/test%d.txt', 'w')",
threadnum);
ret = PyRun_SimpleString(cmd);
ret = PyRun_SimpleString("f.write('%s\\n' % x.__str__())");
sprintf(cmd, "f.write('0x%d\\n')", &myThreadState);
ret = PyRun_SimpleString(cmd);
ret = PyRun_SimpleString("f.close()");

PyThreadState_Swap(NULL);
PyEval_ReleaseLock();


// clean up
// grab the lock
PyEval_AcquireLock();
// swap my thread state out of the interpreter
PyThreadState_Swap(NULL);
// clear out any cruft from thread state object
PyThreadState_Clear(myThreadState);
// delete my thread state object
PyThreadState_Delete(myThreadState);
// release the lock
PyEval_ReleaseLock();

return 0;
}

class CMyWinApp : public CWinApp
{
public:
CMyWinApp() { }
BOOL InitInstance()
{
Py_Initialize();
PyEval_InitThreads();

// save a pointer to the main PyThreadState object
PyThreadState * mainThreadState = PyThreadState_Get();
// release the lock
PyEval_ReleaseLock();

const int nhandles = 100;
HANDLE hnd[nhandles];
CWinThread* pThread[nhandles];
for (int ih = 0; ih < nhandles; ih++)
{
pThread[ih] = AfxBeginThread(MyThread, mainThreadState,
THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED);
pThread[ih]->m_bAutoDelete = false;
pThread[ih]->ResumeThread();

hnd[ih] = pThread[ih]->m_hThread;
}

int nwaits, nfails;
do
{
nwaits = 0;
nfails = 0;
for (int ih = 0; ih < nhandles; ih++)
{
DWORD ret = WaitForSingleObject(hnd[ih], 
INFINITE);
switch (ret)
{
case WAIT_OBJECT_0:
printf("WAIT_OBJECT_0\n");
break;

case WAIT_TIMEOUT:
++nwaits;
printf("WAIT_TIMEOUT\n");
break;

case WAIT_FAILED:
++nfails;
printf("WAIT_FAILED\n");
break;
}
}
}
while (nwaits > 0);
ASSERT(nfails == 0);

// delete all windows threads
for (int ih = 0; ih < nhandles; ++ih)
delete pThread[ih];

PyEval_AcquireLock();
PyThreadState_Swap(mainThreadState);
Py_Finalize();

return TRUE;
};
};

CMyWinApp app;




Debug dump:

'pyembed_test.exe': Loaded
'C:\mdunschen\pyembed

Py_NewInterpreter(), is this a bug in the python core?

2006-07-10 Thread freesteel
/*
Is this a bug in Py_NewInterpreter?

The function below "MyThread" is instantiated from a windows worker
thread, but I don't
think that is relevant.
(I can try this on a linux box, but I would have to compile a python
library with debugging
enabled.)

The following code fragment throws an exception in a debug version of
python:
*/

UINT MyThread(LPVOID lpParam)
{
{
cs.Lock(); // this is a CCriticalSection lock
if (!Py_IsInitialized())
{
Py_Initialize();
PyEval_InitThreads();

// global pointer to the main PyThreadState object
mainThreadState = PyThreadState_Get();
PyEval_ReleaseLock();
}
cs.Unlock();
}

ASSERT(Py_IsInitialized());
ASSERT(PyEval_ThreadsInitialized());
ASSERT(mainThreadState);
threadnum++;

// get the global lock
PyEval_AcquireLock();
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); // Is tis necessary?


PyThreadState_Swap(mainThreadState);
PyThreadState* nts = Py_NewInterpreter();

/*

The exception is thrown inside the above function call:
This statement tries to swap the new threadstate 'tstate' with the
current one
save_tstate = PyThreadState_Swap(tstate);

Inside PyThreadState_Swap the code uses another way
'PyGILState_GetThisThreadState()' to find the current thread state and
compares this with the newly set thread state.
Naturally you would expect the two to be equal but that test fails:
#if defined(Py_DEBUG) && defined(WITH_THREAD)
if (new) {
PyThreadState *check = PyGILState_GetThisThreadState();
if (check && check != new)
Py_FatalError("Invalid thread state for this thread");
}
#endif

The variable 'check' looks as if it is the 'previous' thread state, as
if changing the thread state
is not been done properly. Py_FatalError is called and that's the end.

Is there a mistake in my code, or is there something wrong in how
Py_NewInterpreter is implemented?


Thanks

Martin

PS: Below the rest of my simple test worker thread function.
*/




ASSERT(nts == PyThreadState_Get());

// lock (already locked) - swap in thread state - swap out thread
state - unlock

init_testclass();


int ret = 0;

ret = PyRun_SimpleString("import sys");
ret = PyRun_SimpleString("class redir:\n  def __init__(self, id):\n
self.id = id\n  def write(self, s):\nf = open('stdoutputs_%s.txt' %
self.id, 'a')\nf.write('%s: %s' % (self.id, s))\nf.close()\n");
char str[100];
sprintf(str,"r = redir('0x%x')", &nts);
ret = PyRun_SimpleString(str);
ret = PyRun_SimpleString("sys.stderr = r");
sprintf(str,"s = redir('0x%x')", &nts);
ret = PyRun_SimpleString(str);
ret = PyRun_SimpleString("sys.stdout = s");

ret = PyRun_SimpleString("import testclass");
ret = PyRun_SimpleString("t = testclass.testclass()");
sprintf(str,"print 't = ', t ");
ret = PyRun_SimpleString(str);
ret = PyRun_SimpleString("print t.run(10)");


Py_EndInterpreter(nts);
PyGILState_Release(gstate);
PyEval_ReleaseLock();

return 0;
}

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multithreading windows and embedding python

2006-07-10 Thread freesteel

freesteel wrote:
...
>   pThread[ih] = AfxBeginThread(MyThread, mainThreadState,
> THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED);

...

Here the call to AfxBeginThread is wrong, there is one argument
missing, it should be:

pThread[ih] = AfxBeginThread(MyThread, mainThreadState,
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);

Because there are so many default arguments of similar types the
compiler did not notice that I passed 'CREATE_SUSPENDED' as a stack
size, and use the default 'creation' state of 'start right away' for
the thread.

Don't you love default args and types like 'void*' ?

Martin

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Py_NewInterpreter(), is this a bug in the python core?

2006-07-10 Thread freesteel
Yes, I see that now in the documentation, which to me is quite
confusing.
So, how do you use python in a multithreaded environment, where for
example you want to run some embeded python code from a number of
different C threads?

This article: http://www.linuxjournal.com/article/3641 is quite good,
but must have been written before these PyGILState_* functions.

I only used Py_NewInterpreter to have a fresh 'import sys'.

Somebody enlighten me, please.

Martin

-- 
http://mail.python.org/mailman/listinfo/python-list