20

Ich bin Python-Interpreter in ein C-Programm einbetten. Es kann jedoch vorkommen, dass beim Ausführen eines Python-Skripts über PyRun_SimpleString() eine Endlosschleife ausgeführt wird oder zu lange ausgeführt wird. Betrachten Sie PyRun_SimpleString("while 1: pass"); In der Verhinderung der Blockierung des Hauptprogramms dachte ich, ich könnte den Interpreter in einem Thread ausführen.Eingebettete Python stoppen

Wie höre ich auf, das Python-Skript in eingebetteten Interpreter auszuführen, der in einem Thread ausgeführt wird, ohne den gesamten Prozess zu beenden?

Kann eine Ausnahme an den Interpreter übergeben werden? Sollte ich das Skript unter ein anderes Skript schreiben, das auf Signale hört?

PS: Ich konnte die Python in einem separaten Prozess ausgeführt, aber das ist nicht das, was ich will - es sei denn, es der letzte Ausweg ist ...


Update:

es also, funktioniert jetzt. Danke, Denis Otkidach, noch einmal!

Wenn ich das richtig sehe, haben Sie zwei Dinge zu tun: den Dolmetscher sagen, und return -1 im selben Thread wie Ihre PyRun_SimpleString stop() ausgeführt wird.

Um zu stoppen, hat man ein paar Möglichkeiten: PyErr_SetString(PyExc_KeyboardInterrupt, "...") oder PyErr_SetInterrupt() - die erste könnte Python noch ein paar Anweisungen laufen lassen und dann stoppt es, die spätere stoppt die Ausführung sofort.

Um return -1 verwenden Sie Py_AddPendingCall(), um einen Funktionsaufruf in Python-Ausführung zu injizieren. Die Dokumente erwähnen es seit Version 2.7 und 3.1, aber es läuft auch auf früheren Pythons (2.6 hier). Ab 2.7 und 3.1 sollte es auch threadsicher sein, dh Sie können es aufrufen, ohne GIL (?) Zu erwerben.

So könnte man das Beispiel umschreiben Gebrüll:

int quit() { 
    PyErr_SetInterrupt(); 
    return -1; 
} 

Antwort

10

Sie können Py_AddPendingCall() verwenden, um eine Funktionsereignisausnahmebedingung hinzuzufügen, die beim nächsten Prüfintervall aufgerufen wird (weitere Informationen finden Sie in der Dokumentation unter sys.setcheckinterval()). Hier ist ein Beispiel mit Py_Exit() Aufruf (das funktioniert bei mir der Fall ist, aber wahrscheinlich nicht das, was Sie brauchen), ersetzen Sie es durch Py_Finalize() oder eines PyErr_Set*():

int quit(void *) { 
    Py_Exit(0); 
} 


PyGILState_STATE state = PyGILState_Ensure(); 
Py_AddPendingCall(&quit, NULL); 
PyGILState_Release(state); 

Dies sollte für jeden reinen Python-Code genug sein. Beachten Sie jedoch, dass einige C-Funktionen eine Zeitlang als einzelne Operation ausgeführt werden können (es gab ein Beispiel mit lang laufender Regexp-Suche, aber ich bin mir nicht sicher, ob es noch relevant ist).

+0

Dieser Look * sehr * interessant, aber ist es nicht für die neueste Python? (2.7 alpha stieg gerade heute aus.) Allerdings könnte ich auf Python 3.1 upgraden - aber was dann? Welche Funktion soll ich über 'Py_AddPendingCall()' registrieren? 'PyErr_SetString()'? 'Py_Exit()'? 'Py_Finalize()'? –

+0

Py_AddPendingCall existiert mindestens von Python 2.0 (definiert in ceval.h).Ich habe meiner Antwort einen Beispielcode hinzugefügt. –

+0

Danke! Es klappt! –

1

Nun, die Python-Interpreter aus dem Einbettungs Programm in einem separaten Thread ausgeführt werden müßten, oder Sie werden einfach nie eine Chance zu unterbrechen, den Interpreter bekommen.

Wenn Sie das haben, können Sie möglicherweise einen der Python-API-Ausnahmeaufrufe verwenden, um eine Ausnahme im Interpreter auszulösen? Siehe Python C API Exceptions