PyEval_InitThreads in Python 3: Wie/Wann Sie es nennen? (die saga geht weiter ad nauseam)

Grundsätzlich scheint es massive Verwirrung/Unklarheit über genau, Wann PyEval_InitThreads() soll aufgerufen werden, und welche begleitenden API-Aufrufe benötigt werden. Die offizielle Python Dokumentation ist leider sehr mehrdeutig. Es gibt bereits viele Fragen auf stackoverflow zu diesem Thema, und in der Tat, ich habe persönlich schon auf eine Frage fast identisch, damit es mich nicht besonders Wundern, wenn diese geschlossen ist, als eine doppelte; aber Bedenken Sie, dass es scheint keine definitive Antwort auf diese Frage. (Leider habe ich nicht Guido Van Rossum auf speed-dial.)

Erstens, wir definieren den Umfang der Frage hier: was will ich tun? Naja... ich will schreiben Sie ein Python-Erweiterungsmodul in C, der:

  1. Spawn-worker-threads mit der pthread - API in C
  2. Aufrufen von Python-callbacks innerhalb dieser C-threads

Okay, also lasst uns beginnen mit der Python-docs selbst. Die Python 3.2 docs sagen:

void PyEval_InitThreads()

Initialisieren und dem Erwerb der global interpreter lock. Es sollte
Aufruf in der main-thread vor dem erstellen Sie einen zweiten thread oder sich
in einem anderen thread-Operationen, wie PyEval_ReleaseThread(tstate).
Es ist nicht erforderlich, vor dem Aufruf PyEval_SaveThread() oder
PyEval_RestoreThread().

Also mein Verständnis ist, dass:

  1. Jede C-extension-Modul, welches threads erstellt, muss anrufen
    PyEval_InitThreads() aus dem Haupt-thread, bevor irgendwelche anderen threads
    hervorgebracht
  2. Aufrufen PyEval_InitThreads sperrt die GIL

Also der gesunde Menschenverstand würde uns sagen, dass jede C-extension-Modul, welches threads erstellt, muss call PyEval_InitThreads(), und lassen Sie dann die Globale Interpreter Lock. Okay, scheint einfach genug. So prima-facie -, alles, was erforderlich sein würde, den folgenden code:

PyEval_InitThreads(); /* initialize threading and acquire GIL */
PyEval_ReleaseLock(); /* Release GIL */

Scheint einfach genug... aber leider, die Python 3.2 docs auch sagen, dass PyEval_ReleaseLock wurde nicht. Stattdessen sollten wir nutzen, PyEval_SaveThread zur Freigabe des GIL:

PyThreadState* PyEval_SaveThread()

Release der global interpreter lock (wenn es erstellt wurde und Faden
- Unterstützung aktiviert ist) und setzen Sie die thread-Zustand auf NULL, Rücksendung der
vorherigen thread-Zustand (was nicht NULL ist). Wenn die Sperre
erstellt, die den aktuellen thread muss es erworben haben.

Ähm... okay, also ich denke eine C-extension-Modul muss sagen:

PyEval_InitThreads();
PyThreadState* st = PyEval_SaveThread();


In der Tat, das ist genau das, was diese stackoverflow-Antwort sagt. Außer, wenn ich eigentlich versuchen dies in der Praxis, den Python-interpreter sofort seg-Fehler beim importieren der extension-Modul.    Schön.


Okay, so, jetzt ich ' m aufgeben auf der offiziellen Python-Dokumentation und wandte sich an Google. So, dieser random blog behauptet, alle Sie tun müssen, um aus einer Erweiterungs-Modul ist der Aufruf PyEval_InitThreads(). Natürlich, die Dokumentation behauptet, dass PyEval_InitThreads() erwirbt der GIL, und in der Tat, ein schnelle überprüfung der Quell-code für PyEval_InitThreads() in ceval.c zeigt, dass es in der Tat nennen die interne Funktion take_gil(PyThreadState_GET());

So PyEval_InitThreads() definitiv erwirbt der GIL. Ich würde denken dann, dass Sie unbedingt brauchen, um irgendwie lassen Sie die GIL nach dem Aufruf PyEval_InitThreads().   Aber wie? PyEval_ReleaseLock() ist veraltet, und PyEval_SaveThread() einfach unerklärlich seg-Fehler.

Okay... also vielleicht für einige Grund, die derzeit jenseits meines Verständnisses, eine C-extension module nicht müssen Freisetzung der GIL. Das habe ich versucht... und, wie erwartet, sobald ein anderer thread versucht zu erwerben GIL (mit PyGILState_Ensure), das Programm hängt an einem deadlock. Also ja... Sie wirklich freigeben müssen, die GIL nach dem Aufruf PyEval_InitThreads().

Also wieder, die Frage ist: wie du loslassen GIL nach dem Aufruf PyEval_InitThreads()?

Und generell: was genau ist eine C-extension-Modul muss in der Lage sein, um sicher zu aufrufen von Python-code vom Arbeiter C-threads?

InformationsquelleAutor Channel72 | 2013-03-18
Schreibe einen Kommentar