Unterstützung von freiem Threading in C-API-Erweiterungen
*********************************************************

Seit der Veröffentlichung von 3.13 kann CPython mit abgeschaltetem
*Global Interpreter Lock* (GIL) laufen – in einer Konfiguration namens
*freies Threading*. Dieses Dokument beschreibt, wie du C-API-
Erweiterungen anpasst, damit sie freies Threading unterstützen.


Den Free-Threaded-Build in C erkennen
=====================================

Die C-API von CPython stellt das Makro "Py_GIL_DISABLED" bereit: Im
Free-Threaded-Build ist es auf "1" definiert, im regulären Build ist
es nicht definiert. Du kannst es verwenden, um Code einzuschalten, der
nur im Free-Threaded-Build läuft:

   #ifdef Py_GIL_DISABLED
   /* code that only runs in the free-threaded build */
   #endif

Bemerkung:

  Unter Windows wird dieses Makro nicht automatisch definiert, sondern
  muss dem Compiler beim Bauen angegeben werden. Mit der Funktion
  "sysconfig.get_config_var()" lässt sich feststellen, ob das Makro
  für den gerade laufenden Interpreter definiert war.


Modulinitialisierung
====================

Erweiterungsmodule müssen ausdrücklich angeben, dass sie den Betrieb
mit abgeschaltetem GIL unterstützen. Andernfalls löst der Import der
Erweiterung eine Warnung aus und schaltet den GIL zur Laufzeit ein.

Es gibt zwei Wege, anzugeben, dass ein Erweiterungsmodul den Betrieb
mit abgeschaltetem GIL unterstützt – je nachdem, ob die Erweiterung
eine mehrphasige oder eine einphasige Initialisierung verwendet.


Mehrphasige Initialisierung
---------------------------

Erweiterungen, die eine mehrphasige Initialisierung verwenden
(Funktionen wie "PyModuleDef_Init()", der Export-Haken
"PyModExport_*", "PyModule_FromSlotsAndSpec()"), sollten in der
Moduldefinition einen Slot "Py_mod_gil" ergänzen. Unterstützt deine
Erweiterung auch ältere CPython-Versionen, solltest du den Slot mit
einer Prüfung auf "PY_VERSION_HEX" absichern.

   static struct PyModuleDef_Slot module_slots[] = {
       ...
   #if PY_VERSION_HEX >= 0x030D0000
       {Py_mod_gil, Py_MOD_GIL_NOT_USED},
   #endif
       {0, NULL}
   };


Einphasige Initialisierung
--------------------------

Erweiterungen, die die alte einphasige Initialisierung verwenden (also
"PyModule_Create()"), sollten "PyUnstable_Module_SetGIL()" aufrufen,
um anzugeben, dass sie den Betrieb mit abgeschaltetem GIL
unterstützen. Die Funktion ist nur im Free-Threaded-Build definiert.
Du solltest den Aufruf daher mit "#ifdef Py_GIL_DISABLED" absichern,
um Kompilierfehler im regulären Build zu vermeiden.

   static struct PyModuleDef moduledef = {
       PyModuleDef_HEAD_INIT,
       ...
   };

   PyMODINIT_FUNC
   PyInit_mymodule(void)
   {
       PyObject *m = PyModule_Create(&moduledef);
       if (m == NULL) {
           return NULL;
       }
   #ifdef Py_GIL_DISABLED
       PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
   #endif
       return m;
   }


Allgemeine Richtlinien zur API
==============================

Der größte Teil der C-API ist threadsicher, es gibt aber einige
Ausnahmen.

* **Strukturfelder**: Der direkte Zugriff auf Felder in Objekten oder
  Strukturen der Python-C-API ist nicht threadsicher, wenn das Feld
  gleichzeitig verändert werden kann.

* **Makros**: Zugriffsmakros wie "PyList_GET_ITEM" und
  "PyList_SET_ITEM" sowie Makros wie "PySequence_Fast_GET_SIZE", die
  das von "PySequence_Fast()" zurückgegebene Objekt verwenden, führen
  keine Fehlerprüfung und keine Sperrung durch. Diese Makros sind
  nicht threadsicher, wenn das Containerobjekt gleichzeitig verändert
  werden kann.

* **Entlehnte Referenzen**: C-API-Funktionen, die *entlehnte
  Referenzen* zurückgeben, sind möglicherweise nicht threadsicher,
  wenn das umgebende Objekt gleichzeitig verändert wird. Näheres steht
  im Abschnitt über entlehnte Referenzen.


Threadsicherheit von Containern
-------------------------------

Container wie "PyListObject", "PyDictObject" und "PySetObject" sperren
im Free-Threaded-Build intern. So sperrt zum Beispiel
"PyList_Append()" die Liste, bevor ein Element angehängt wird.


"PyDict_Next"
~~~~~~~~~~~~~

Eine bemerkenswerte Ausnahme ist "PyDict_Next()", das das Wörterbuch
nicht sperrt. Du solltest "Py_BEGIN_CRITICAL_SECTION" verwenden, um
das Wörterbuch beim Iterieren zu schützen, wenn es gleichzeitig
verändert werden kann:

   Py_BEGIN_CRITICAL_SECTION(dict);
   PyObject *key, *value;
   Py_ssize_t pos = 0;
   while (PyDict_Next(dict, &pos, &key, &value)) {
       ...
   }
   Py_END_CRITICAL_SECTION();


Entlehnte Referenzen
====================

Manche C-API-Funktionen geben *entlehnte Referenzen* zurück. Diese
APIs sind nicht threadsicher, wenn das umgebende Objekt gleichzeitig
verändert wird. So ist es zum Beispiel nicht sicher,
"PyList_GetItem()" zu verwenden, wenn die Liste gleichzeitig verändert
werden kann.

Die folgende Tabelle führt einige APIs mit entlehnten Referenzen und
ihren Ersatz auf, der *starke Referenzen* zurückgibt.

+-------------------------------------+-------------------------------------+
| API mit entlehnter Referenz         | API mit starker Referenz            |
|=====================================|=====================================|
| "PyList_GetItem()"                  | "PyList_GetItemRef()"               |
+-------------------------------------+-------------------------------------+
| "PyList_GET_ITEM()"                 | "PyList_GetItemRef()"               |
+-------------------------------------+-------------------------------------+
| "PyDict_GetItem()"                  | "PyDict_GetItemRef()"               |
+-------------------------------------+-------------------------------------+
| "PyDict_GetItemWithError()"         | "PyDict_GetItemRef()"               |
+-------------------------------------+-------------------------------------+
| "PyDict_GetItemString()"            | "PyDict_GetItemStringRef()"         |
+-------------------------------------+-------------------------------------+
| "PyDict_SetDefault()"               | "PyDict_SetDefaultRef()"            |
+-------------------------------------+-------------------------------------+
| "PyDict_Next()"                     | keine (siehe PyDict_Next)           |
+-------------------------------------+-------------------------------------+
| "PyWeakref_GetObject()"             | "PyWeakref_GetRef()"                |
+-------------------------------------+-------------------------------------+
| "PyWeakref_GET_OBJECT()"            | "PyWeakref_GetRef()"                |
+-------------------------------------+-------------------------------------+
| "PyImport_AddModule()"              | "PyImport_AddModuleRef()"           |
+-------------------------------------+-------------------------------------+
| "PyCell_GET()"                      | "PyCell_Get()"                      |
+-------------------------------------+-------------------------------------+

Nicht alle APIs, die entlehnte Referenzen zurückgeben, sind
problematisch. So ist zum Beispiel "PyTuple_GetItem()" sicher, weil
Tupel unveränderlich sind. Ebenso sind nicht alle Verwendungen der
obigen APIs problematisch. "PyDict_GetItem()" wird zum Beispiel oft
verwendet, um Wörterbücher mit Schlüsselwortargumenten in
Funktionsaufrufen zu zerlegen. Diese Wörterbücher sind praktisch
privat (für andere Threads nicht zugänglich), sodass entlehnte
Referenzen in diesem Zusammenhang sicher sind.

Einige dieser Funktionen wurden in Python 3.13 ergänzt. Du kannst das
Paket pythoncapi-compat verwenden, um Implementierungen dieser
Funktionen für ältere Python-Versionen zu erhalten.


APIs zur Speicherverwaltung
===========================

Die C-API von Python zur Speicherverwaltung stellt Funktionen in drei
verschiedenen Anforderungsbereichen bereit: „raw“, „mem“ und „object“.
Aus Gründen der Threadsicherheit verlangt der Free-Threaded-Build,
dass nur Python-Objekte über den object-Bereich angelegt werden und
dass alle Python-Objekte über diesen Bereich angelegt werden. Das
unterscheidet sich von früheren Python-Versionen, in denen das nur
eine Empfehlung und keine harte Anforderung war.

Bemerkung:

  Suche in deiner Erweiterung nach Verwendungen von
  "PyObject_Malloc()" und prüfe, ob der angeforderte Speicher für
  Python-Objekte verwendet wird. Verwende "PyMem_Malloc()" anstelle
  von "PyObject_Malloc()", um Puffer anzufordern.


APIs für Thread-Zustand und GIL
===============================

Python bietet eine Reihe von Funktionen und Makros, um den Thread-
Zustand und den GIL zu verwalten, etwa:

* "PyThreadState_Ensure()", "PyThreadState_EnsureFromView()" und
  "PyThreadState_Release()"

* "PyGILState_Ensure()" und "PyGILState_Release()"

* "PyEval_SaveThread()" und "PyEval_RestoreThread()"

* "Py_BEGIN_ALLOW_THREADS" und "Py_END_ALLOW_THREADS"

Diese Funktionen sollten auch im Free-Threaded-Build verwendet werden,
um den Thread-Zustand zu verwalten, selbst wenn der *GIL* abgeschaltet
ist. Erzeugst du zum Beispiel einen Thread außerhalb von Python, musst
du "PyThreadState_Ensure()" aufrufen, bevor du in die Python-API
hineinrufst, damit der Thread einen gültigen Python-Thread-Zustand
hat.

Du solltest "PyEval_SaveThread()" oder "Py_BEGIN_ALLOW_THREADS"
weiterhin um blockierende Vorgänge wie Ein- und Ausgabe oder das
Anfordern von Sperren herum aufrufen, damit andere Threads die
*zyklische Garbage Collection* ausführen können.


Internen Zustand einer Erweiterung schützen
===========================================

Deine Erweiterung hat möglicherweise internen Zustand, der früher
durch den GIL geschützt war. Vielleicht musst du Sperren ergänzen, um
diesen Zustand zu schützen. Wie das aussieht, hängt von deiner
Erweiterung ab, aber einige verbreitete Muster sind:

* **Zwischenspeicher**: Globale Zwischenspeicher sind eine häufige
  Quelle gemeinsamen Zustands. Erwäge, den Zwischenspeicher mit einer
  Sperre zu schützen oder ihn im Free-Threaded-Build abzuschalten,
  wenn er für die Leistung nicht entscheidend ist.

* **Globaler Zustand**: Globaler Zustand muss möglicherweise mit einer
  Sperre geschützt oder in thread-lokalen Speicher verschoben werden.
  C11 und C++11 bieten "thread_local" beziehungsweise "_Thread_local"
  für thread-lokalen Speicher.


Kritische Abschnitte
====================

Im Free-Threaded-Build bietet CPython einen Mechanismus namens
„kritische Abschnitte“, um Daten zu schützen, die sonst durch den GIL
geschützt wären. Autoren von Erweiterungen haben mit der internen
Implementierung der kritischen Abschnitte zwar möglicherweise nie
direkt zu tun, aber ihr Verhalten zu verstehen ist entscheidend, wenn
du bestimmte C-API-Funktionen verwendest oder im Free-Threaded-Build
gemeinsamen Zustand verwaltest.


Was sind kritische Abschnitte?
------------------------------

Vom Konzept her wirken kritische Abschnitte wie eine Schicht zur
Verklemmungsvermeidung, die auf einfachen Mutexen aufsetzt. Jeder
Thread führt einen Stapel der aktiven kritischen Abschnitte. Muss ein
Thread eine Sperre anfordern, die zu einem kritischen Abschnitt gehört
(etwa implizit beim Aufruf einer threadsicheren C-API-Funktion wie
"PyDict_SetItem()" oder ausdrücklich über die Makros), versucht er,
den darunterliegenden Mutex anzufordern.


Kritische Abschnitte verwenden
------------------------------

Die wichtigsten APIs für kritische Abschnitte sind:

* "Py_BEGIN_CRITICAL_SECTION" und "Py_END_CRITICAL_SECTION" – um ein
  einzelnes Objekt zu sperren

* "Py_BEGIN_CRITICAL_SECTION2" und "Py_END_CRITICAL_SECTION2" – um
  zwei Objekte gleichzeitig zu sperren

Diese Makros müssen paarweise verwendet werden und im selben
C-Gültigkeitsbereich stehen, weil sie einen neuen lokalen
Gültigkeitsbereich eröffnen. In Builds ohne freies Threading tun diese
Makros nichts, sie lassen sich also gefahrlos in Code ergänzen, der
beide Build-Arten unterstützen muss.

Ein verbreiteter Einsatz eines kritischen Abschnitts ist, ein Objekt
beim Zugriff auf eines seiner internen Attribute zu sperren. Hat ein
Erweiterungstyp zum Beispiel ein internes Feld count, könntest du beim
Lesen oder Schreiben dieses Feldes einen kritischen Abschnitt
verwenden:

   // read the count, returns new reference to internal count value
   PyObject *result;
   Py_BEGIN_CRITICAL_SECTION(obj);
   result = Py_NewRef(obj->count);
   Py_END_CRITICAL_SECTION();
   return result;

   // write the count, consumes reference from new_count
   Py_BEGIN_CRITICAL_SECTION(obj);
   obj->count = new_count;
   Py_END_CRITICAL_SECTION();


Wie kritische Abschnitte arbeiten
---------------------------------

Anders als herkömmliche Sperren sichern kritische Abschnitte nicht
über ihre gesamte Dauer ausschließlichen Zugriff zu. Würde ein Thread
blockieren, während er einen kritischen Abschnitt hält (etwa indem er
eine weitere Sperre anfordert oder Ein- und Ausgabe betreibt), wird
der kritische Abschnitt vorübergehend ausgesetzt – alle Sperren werden
freigegeben – und nach Abschluss des blockierenden Vorgangs wieder
aufgenommen.

Dieses Verhalten ähnelt dem, was beim GIL geschieht, wenn ein Thread
einen blockierenden Aufruf macht. Die wesentlichen Unterschiede sind:

* Kritische Abschnitte arbeiten je Objekt und nicht global

* Kritische Abschnitte folgen innerhalb jedes Threads einer
  Stapeldisziplin (die Makros „begin“ und „end“ erzwingen das, weil
  sie paarweise und im selben Gültigkeitsbereich stehen müssen)

* Kritische Abschnitte geben Sperren rund um möglicherweise
  blockierende Vorgänge automatisch frei und fordern sie danach wieder
  an


Verklemmungsvermeidung
----------------------

Kritische Abschnitte helfen auf zwei Wege, Verklemmungen zu vermeiden:

1. Versucht ein Thread, eine Sperre anzufordern, die bereits ein
   anderer Thread hält, setzt er zunächst alle seine aktiven
   kritischen Abschnitte aus und gibt deren Sperren vorübergehend frei

2. Ist der blockierende Vorgang abgeschlossen, wird zuerst nur der
   oberste kritische Abschnitt wieder angefordert

Das heißt, dass du dich nicht darauf verlassen kannst, mit
verschachtelten kritischen Abschnitten mehrere Objekte gleichzeitig zu
sperren, weil der innere kritische Abschnitt die äußeren aussetzen
kann. Verwende stattdessen "Py_BEGIN_CRITICAL_SECTION2", um zwei
Objekte gleichzeitig zu sperren.

Beachte, dass die oben beschriebenen Sperren ausschließlich Sperren
auf Basis von "PyMutex" sind. Die Implementierung der kritischen
Abschnitte weiß nichts von anderen möglicherweise verwendeten
Sperrmechanismen, etwa POSIX-Mutexen, und beeinflusst sie nicht.
Beachte außerdem: Das Blockieren an einem beliebigen "PyMutex" setzt
die kritischen Abschnitte zwar aus, freigegeben werden aber nur die
Mutexe, die Teil der kritischen Abschnitte sind. Wird ein "PyMutex"
ohne kritischen Abschnitt verwendet, wird er nicht freigegeben und
erhält daher nicht dieselbe Verklemmungsvermeidung.


Wichtige Überlegungen
---------------------

* Kritische Abschnitte können ihre Sperren vorübergehend freigeben und
  es anderen Threads so erlauben, die geschützten Daten zu verändern.
  Sei vorsichtig mit Annahmen über den Zustand der Daten nach
  Vorgängen, die blockieren könnten.

* Weil Sperren vorübergehend freigegeben (ausgesetzt) werden können,
  sichert das Betreten eines kritischen Abschnitts über die gesamte
  Dauer des Abschnitts keinen ausschließlichen Zugriff auf die
  geschützte Ressource zu. Ruft Code innerhalb eines kritischen
  Abschnitts eine andere Funktion auf, die blockiert (etwa eine
  weitere Sperre anfordert oder blockierende Ein- und Ausgabe
  betreibt), werden alle Sperren freigegeben, die der Thread über
  kritische Abschnitte hält. Das ähnelt dem Umstand, dass der GIL
  während blockierender Aufrufe freigegeben werden kann.

* Nur die Sperre beziehungsweise die Sperren des zuletzt betretenen
  (obersten) kritischen Abschnitts sind zu jedem Zeitpunkt garantiert
  gehalten. Die Sperren äußerer, verschachtelter kritischer Abschnitte
  können ausgesetzt sein.

* Mit diesen APIs kannst du höchstens zwei Objekte gleichzeitig
  sperren. Musst du mehr Objekte sperren, musst du deinen Code
  umbauen.

* Kritische Abschnitte verklemmen zwar nicht, wenn du versuchst,
  dasselbe Objekt zweimal zu sperren, sind für diesen Anwendungsfall
  aber weniger effizient als eigens dafür gebaute
  wiedereintrittsfähige Sperren.

* Bei "Py_BEGIN_CRITICAL_SECTION2" wirkt sich die Reihenfolge der
  Objekte nicht auf die Korrektheit aus (die Implementierung erledigt
  die Verklemmungsvermeidung), es ist aber gute Praxis, Objekte immer
  in derselben Reihenfolge zu sperren.

* Bedenke, dass die Makros für kritische Abschnitte vor allem dafür da
  sind, den Zugriff auf *Python-Objekte* zu schützen, die in interne
  CPython-Vorgänge mit den oben beschriebenen Verklemmungsgefahren
  verwickelt sein können. Um rein internen Zustand einer Erweiterung
  zu schützen, sind gewöhnliche Mutexe oder andere
  Synchronisationsprimitive möglicherweise passender.


Sperren je Objekt ("ob_mutex")
------------------------------

Im Free-Threaded-Build enthält jedes Python-Objekt ein Feld "ob_mutex"
vom Typ "PyMutex". Dieser Mutex ist **der Verwendung durch die API für
kritische Abschnitte vorbehalten** ("Py_BEGIN_CRITICAL_SECTION" /
"Py_END_CRITICAL_SECTION").

Warnung:

  Sperre "ob_mutex" **nicht** direkt mit
  "PyMutex_Lock(&obj->ob_mutex)". Direkte "PyMutex_Lock"-Aufrufe mit
  der API für kritische Abschnitte am selben Mutex zu mischen, kann
  Verklemmungen verursachen.

Selbst wenn dein eigener Code für einen bestimmten Objekttyp nie
kritische Abschnitte verwendet, **kann das Innere von CPython die API
für kritische Abschnitte auf jedem Python-Objekt verwenden**.

Braucht dein Erweiterungstyp eine eigene Sperre, ergänze in deiner
Objektstruktur ein eigenes Feld vom Typ "PyMutex" (oder ein anderes
Synchronisationsprimitiv). "PyMutex" ist sehr leichtgewichtig, ein
weiterer kostet also so gut wie nichts.


Erweiterungen für den Free-Threaded-Build bauen
===============================================

C-API-Erweiterungen müssen speziell für den Free-Threaded-Build gebaut
werden. Die Wheels, dynamischen Bibliotheken und Programmdateien sind
durch ein angehängtes "t" gekennzeichnet.

* pypa/manylinux unterstützt den Free-Threaded-Build, mit angehängtem
  "t", etwa "python3.14t".

* pypa/cibuildwheel unterstützt das Bauen von Wheels für den Free-
  Threaded-Build von Python 3.14 und neuer.


Eingeschränkte C-API und stabiles ABI
-------------------------------------

Der Free-Threaded-Build unterstützt derzeit weder die eingeschränkte
C-API noch das stabile ABI. Wenn du deine Erweiterung mit setuptools
baust und derzeit "py_limited_api=True" setzt, kannst du
"py_limited_api=not sysconfig.get_config_var("Py_GIL_DISABLED")"
verwenden, um beim Bauen mit dem Free-Threaded-Build auf die
eingeschränkte API zu verzichten.

Bemerkung:

  Du musst eigene Wheels speziell für den Free-Threaded-Build bauen.
  Wenn du derzeit das stabile ABI verwendest, kannst du weiterhin ein
  einzelnes Wheel für mehrere Python-Versionen ohne freies Threading
  bauen.


Windows
-------

Wegen einer Einschränkung des offiziellen Windows-
Installationsprogramms musst du "Py_GIL_DISABLED=1" beim Bauen von
Erweiterungen aus den Quellen von Hand definieren.

Siehe auch:

  Porting Extension Modules to Support Free-Threading: eine von der
  Gemeinschaft gepflegte Portierungsanleitung für Autoren von
  Erweiterungen.
