Frage

Ich bin Einbettung Python-Interpreter zu einem C-Programm. Es kann jedoch vorkommen, dass während einige Python-Skript über PyRun_SimpleString() ausgeführt wird in Endlosschleife laufen oder zu lange auszuführen. Betrachten PyRun_SimpleString("while 1: pass"); im Hauptprogramm verhindern zu blockieren Ich dachte, ich könnte den Interpreter in einem Thread ausgeführt werden.

Wie verhindere ich das Python-Skript in einem Thread ausgeführt wird in eingebetteten Interpreter ausgeführt wird, ohne den gesamten Prozess zu töten?

Ist es möglich, eine Ausnahme von der Dolmetscher zu übergeben? Soll ich das Skript unter einem anderen Skript wickeln, die auf Signale hören würde?

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


Update:

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

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

.

zu stoppen, hat man ein paar Möglichkeiten: PyErr_SetString(PyExc_KeyboardInterrupt, "...") oder PyErr_SetInterrupt() - die erste Python verlassen könnte noch ein paar Anweisungen ausgeführt und dann hält er an, die später man sofort die Ausführung stoppt

.

Um return -1 Sie Py_AddPendingCall() verwenden, um einen Funktionsaufruf in Python Ausführung zu injizieren. Die Dokumente sind zu erwähnen es seit Version 2.7 und 3.1, aber es läuft auf früheren Pythons auch (2.6 hier). Von 2.7 und 3.1 sollte es auch Thread-sicher sein, was bedeutet, können Sie es ohne den Erwerb GIL nennen kann (?).

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

int quit() {
    PyErr_SetInterrupt();
    return -1;
}
War es hilfreich?

Lösung

Sie können Py_AddPendingCall() verwenden, um eine Funktion Anhebung Ausnahme hinzuzufügen auf der nächsten Überprüfungsintervall (siehe docs auf sys.setcheckinterval() für weitere Informationen) genannt werden. 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. Aber beachten Sie, dass einige C-Funktionen für eine Weile als eine einzelne Operation ausgeführt werden können (es gab ein Beispiel mit langer Laufzeit regexp Suche, aber ich bin nicht sicher, es ist immer noch relevant).

Andere Tipps

Nun, der Python-Interpreter würde in einem separaten Thread aus dem Einbettungsprogramm zu laufen, oder Sie werden einfach bekommen nie eine Chance, den Interpreter zu unterbrechen.

Wenn Sie das haben, können Sie vielleicht eine der Python API Ausnahme verwenden ruft eine Ausnahme im Interpreter auslösen? Siehe Python-C-API Ausnahmen

Ich wollte jeden aktiv ausgeführt Python Code-Block zu unterbrechen zu können, einschließlich einer Endlosschleife Cancelling oder nur einig lang andauernden Code. In meiner Anwendung, Python-Code Single-Thread wird vorgelegt und bewertet. Ein Interrupt-Request kann jederzeit kommen. Diese Frage und Antwort war entscheidend hilft mir, dass tatsächlich zu erreichen.

auf diese Frage im Jahr 2019 sucht, ist hier die Lösung nicht für mich arbeiten; Ich habe versucht, Py_AddPendingCall(&quit, NULL); in ganz ein paar verschiedenen Möglichkeiten zu nutzen, aber die aufgerufene Funktion nicht wie erwartet oder überhaupt ausgeführt wird. Dies führte zu der Python-Engine zu hängen und schließlich abstürzen, wenn ich Py_FinalizeEx() vorgelegt. Schließlich fand ich, was ich in diesem sehr nützlichen auf eine ähnliche Frage beantworten.

Nachdem ich den Python Motor starten, rufe ich die Thread-ID das threading Paket in Python-Code. Ich analysieren, dass in einen c long-Wert und speichern Sie es.

Die Interrupt-Funktion ist eigentlich ganz einfach:
PyGILState_Ensure()
PyThreadState_SetAsyncExc(threadId, PyExc_Exception) mit der Thread-ID, die ich von früher und einem allgemeinen Ausnahmetyp
speichern PyGILState_Release()

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top