multithreading windows and embedding python

freesteel zabaione at uk2.net
Mon Jun 19 12:31:06 EDT 2006


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 <afxmt.h>
#include <afxwin.h>
#include <stdio.h>
#include <Python.h>
#include <Windows.h>
#include <process.h>

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_test\Debug\pyembed_test.exe', Symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\mscoree.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\advapi32.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\rpcrt4.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\user32.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\gdi32.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\comctl32.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\shlwapi.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\msvcrt.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\oleacc.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\msvcp60.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\ole32.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\oleaut32.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\winspool.drv', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\comdlg32.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\shell32.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\python24.dll', No
symbols loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\msvcr71.dll', Symbols
loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll',
No symbols loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorwks.dll', No symbols
loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\fusion.dll', No symbols
loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorlib.dll', No symbols
loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\assembly\NativeImages1_v1.1.4322\mscorlib\1.0.5000.0__b77a5c561934e089_ca105f6f\mscorlib.dll',
No symbols loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\diasymreader.dll', No
symbols loaded.
'DefaultDomain': Loaded
'c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll', No symbols
loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorsn.dll', No symbols
loaded.
'pyembed_test': Loaded
'c:\mdunschen\pyembed_test\Debug\pyembed_test.exe', Symbols loaded.
'pyembed_test.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorjit.dll', No symbols
loaded.
'pyembed_test.exe': Loaded 'C:\WINDOWS\system32\uxtheme.dll', No
symbols loaded.
The thread '_threadstartex' (0x500) has exited with code 0 (0x0).
The thread '_threadstartex' (0xadc) has exited with code 0 (0x0).
The thread '<No Name>' (0xadc) has exited with code 0 (0x0).
The thread '<No Name>' (0x500) has exited with code 0 (0x0).
The thread '_threadstartex' (0x928) has exited with code 0 (0x0).
The thread '<No Name>' (0x928) has exited with code 0 (0x0).
The thread '_threadstartex' (0xe48) has exited with code 0 (0x0).
The thread '<No Name>' (0xe48) has exited with code 0 (0x0).
The thread '_threadstartex' (0x984) has exited with code 0 (0x0).
The thread '<No Name>' (0x984) has exited with code 0 (0x0).
The thread '_threadstartex' (0x108) has exited with code 0 (0x0).
HEAP[pyembed_test.exe]: HEAP: Free Heap block eb5bd8 modified at eb5c24
after it was freed
Unhandled exception at 0x7c901230 in pyembed_test.exe: User breakpoint.




Stack dump:
>	pyembed_test.exe!_heap_alloc_dbg(unsigned int nSize=15400960, int nBlockUse=1073741920, const char * szFileName=0x00000064, int nLine=1242368)  Line 359 + 0x1e	C
 	pyembed_test.exe!_heap_alloc_base(unsigned int size=100)  Line 212	C
 	pyembed_test.exe!_heap_alloc_dbg(unsigned int nSize=64, int
nBlockUse=12582916, const char * szFileName=0x004c4dd4, int nLine=311)
Line 397 + 0x9	C
 	pyembed_test.exe!_nh_malloc_dbg(unsigned int nSize=64, int nhFlag=0,
int nBlockUse=12582916, const char * szFileName=0x004c4dd4, int
nLine=311)  Line 260 + 0x15	C
 	pyembed_test.exe!_malloc_dbg(unsigned int nSize=64, int
nBlockUse=12582916, const char * szFileName=0x004c4dd4, int nLine=311)
Line 176 + 0x1b	C
 	pyembed_test.exe!operator new(unsigned int nSize=64, int
nType=12582916, const char * lpszFileName=0x004c4dd4, int nLine=311)
Line 403 + 0x15	C++
 	pyembed_test.exe!CObject::operator new(unsigned int nSize=64, const
char * lpszFileName=0x004c4dd4, int nLine=311)  Line 93 + 0x16	C++
 	pyembed_test.exe!AfxBeginThread(unsigned int (void *)*
pfnThreadProc=0x00401b80, void * pParam=0x00df7b10, int nPriority=0,
unsigned int nStackSize=4, unsigned long dwCreateFlags=0,
_SECURITY_ATTRIBUTES * lpSecurityAttrs=0x00000000)  Line 311 + 0x11	C++
 	00aaa43d()
 	pyembed_test.exe!CMyWinApp::InitInstance() Line 87 + 0x26 bytes	C++
 	pyembed_test.exe!AfxWinMain(HINSTANCE__ * hInstance=0x00400000,
HINSTANCE__ * hPrevInstance=0x00000000, char * lpCmdLine=0x00141f12,
int nCmdShow=5)  Line 39 + 0xb	C++
 	pyembed_test.exe!WinMain(HINSTANCE__ * hInstance=0x00400000,
HINSTANCE__ * hPrevInstance=0x00000000, char * lpCmdLine=0x00141f12,
int nCmdShow=5)  Line 25	C++
 	pyembed_test.exe!WinMainCRTStartup()  Line 251 + 0x30	C




More information about the Python-list mailing list