Embedded Python und Thread Problem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
brachaan
User
Beiträge: 4
Registriert: Montag 15. Mai 2006, 10:27

Hallo allerseits,

ich habe eine Anwendung, die Python als eingebettete Scriptsprache nutzt. Dazu wird in einem vordefinierten Python Script eine Funktion "start" definiert, die von meiner Anwendung gerufen wird.
Die Ausführung dieses Aufrufs liegt wiederum in einem eigenen C-Thread, damit meine Anwendung nicht blockiert wird während der Ausführung des Scripts.
Der Code im C-Thread sieht so aus:

Code: Alles auswählen

UINT ScriptThreadProc(LPVOID lParam)
{
	bool error = false;
	ScriptThreadData * std = (ScriptThreadData*) lParam;

	PyObject *pStart = std->mainScriptMethod;
	PyObject * runObject = 0;

         // Create new Threadstate object
	PyThreadState * tstate = PyThreadState_New(std->sc->m_pMainInterpreterState);

         // Swap in my Threadstate
	PyEval_AcquireLock();
	PyThreadState * temp = PyThreadState_Swap(tstate);

         
         // The script execution is started here
	if(pStart && PyCallable_Check(pStart))
	{
		runObject = PyObject_CallObject(pStart, NULL);  // call the "start" function in the python script
	}
	if(runObject)
		Py_DECREF(runObject);   // clear the object, if script execution finished 


	PyEval_ReleaseThread(tstate);  // release the current thread state and reset it to NULL

         // clear and free the thread state
	PyEval_AcquireLock();
		PyThreadState_Clear(tstate);
		PyThreadState_Delete(tstate);
	PyEval_ReleaseLock();

	return 0;
}
Das Programm läuft soweit im Release Mode auch sehr gut, im Debug Modus stürtz es allerdings regelmässig ab mit der Fehlermeldung: "Fatal Python error: Invalid thread state for this thread"
Der Absturz kommt aus der Python Library aus dieser Funktion:

Code: Alles auswählen

PyThreadState *
PyThreadState_Swap(PyThreadState *new)
{
	PyThreadState *old = _PyThreadState_Current;

	_PyThreadState_Current = new;
	/* It should not be possible for more than one thread state
	   to be used for a thread.  Check this the best we can in debug
	   builds.
	*/
#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
	return old;
Durch die Zeile
#if defined(Py_DEBUG) && defined(WITH_THREAD)
ist auch klar, warum der Absturz nur im Debugmode auftritt.
Es scheint so, als würde sich Python darüber beschweren, dass es für diesen Thread mehrere Thread-States gibt. Die Frage ist aber, wer erstellt noch neue Thread-States für meinen Thread? Und warum ist das für Python ein Problem?

Weiterhin ist dabei seltsam, dass der obige Code immer einmal fehlerfrei ausgeführt wird. Danach tritt der Fehler abhängig vom Script auf.
Besteht das Script z.B. nur aus der Zeile:
x = ' ' *2000000
stüzt es bereits bei der zweiten Ausführung ab, aber bei der Zeile:
print "hallo"
stürzt es erst bei der dritten Ausführung ab. Und das sicher reproduzierbar.

Ich hoffe, ihr könnt mir da irgendwie weiterhelfen.
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Vielleicht(!) hilft das weiter: http://www.linuxjournal.com/article/3641
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hallo,

puh, ganz schön kniffelig.

Eine Frage hätte ich: Was ist "check"?
Aber ich glaube, daß ich Dir nicht helfen kann und wenn Du hier im Forum keine Hilfe findest, würde ich mich mal an folgende SIG wenden: http://mail.python.org/mailman/listinfo/c++-sig/
Die C++-SIG hat zwar einen anderen Focus, aber die Leute werden Dir am ehesten helfen können und das Archive behandelt auch ähnliche Probleme.

Gruß,
Christian
brachaan
User
Beiträge: 4
Registriert: Montag 15. Mai 2006, 10:27

Danke für die Antwort, aber nach diesem Artikel ist mein Thread bereits aufgebaut.
Die grobe Struktur:
1. create new thread state-object
2. swap in the new threat state-object
3. execute python code
4. swap out the thread state object
5. clean up the thread state object

Diese grobe Struktur wird ja eingehalten.
Und wie bereits gesagt, das Programm läuft fehlerfrei im Releasemodus.
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Ich glaube eher, dass im Releasemodus Py_DEBUG nicht gesetzt ist und daher der Test gar nicht ausgeführt wird.
brachaan
User
Beiträge: 4
Registriert: Montag 15. Mai 2006, 10:27

CM hat geschrieben: ...
Eine Frage hätte ich: Was ist "check"?
...
Du meinst das hier?
PyThreadState *check = PyGILState_GetThisThreadState();
if (check && check != new)
Das ist aus der Python lib selbst. Genau aus dem File pystate.c. An dieser Stelle wird geprüft, ob es für den aktuellen Thread bereits einen Threadstate gibt und wenn, ob er gleich dem ist, der zum aktuellen State gemacht werden soll.
Offensichtlich darf es also nicht mehrere Threadstates für einen Thread geben.

Problematisch ist nur, dass ich wirklich nur den einen Threadstate anlege und auch wieder zerstöre. Trotzdem meint Python, es gibt noch mind. einen weiteren Threadstate beim zweiten oder dritten Aufruf.

Viele Grüsse
brachaan
User
Beiträge: 4
Registriert: Montag 15. Mai 2006, 10:27

Joghurt hat geschrieben:Ich glaube eher, dass im Releasemodus Py_DEBUG nicht gesetzt ist und daher der Test gar nicht ausgeführt wird.
Na, davon geh ich doch aus :)
Die Frage ist auch vielmehr, wo kommt der weitere Threadstate her?
Antworten