Die globale Welt von 1970

Es ist schon klar, dass eigentlich alles “aus der Historie” entstanden ist. Kein System, das älter als 5 Jahre ist, leidet nicht an seinen Design-Entscheidungen aus der Vergangenheit.

Wie auch immer … manche Dinge sind schon ein bisschen unverzeihlich, wenn wir im 21. Jahrhundert immer noch mit “globalen” Zuständen und Variablen konfrontiert sind, nur weil um 1970 noch keiner objektorientiert nachgedacht hat.

Als Unix “Prozesse” als logische Einheit einführte, muss das wohl der heilige Gral und etwas überaus Fortschrittliches gewesen sein.

Und so wie in der Physik Atome noch vor 200 Jahren wirklich unteilbar waren, so dachte niemand daran, dass Prozesse einmal logische Untereinheiten - heute als Threads bekannt - haben würden.

Und so wurde die dunkle Saat in Form von globalen Variablen in alle APIs eingesetzt. Globale Signalhandler, globale Directory/File-Creation-Masks , und was fork() in einem Threading-Kontext alles verbrechen kann, will ich gar nicht ausführen …

Windows NT aus den 1990ern hätte hier ein Messias sein können und tatsächlich, Threads und ganz allgemein HANDLEs und TOKEN lassen uns Zustände schön objektorientiert zuordnent.

… alle Zustände? Nein! Eine kleine Gruppe von Schnittstellen wiedersetzt sich hartnäckig dem guten Konzept und wirft letztendlich wieder alles um.

Privilegien, die nur prozessweit aktivierbar sind, APIs die den Thread-Token ignorieren und sich auf den originalen Prozess-Token fixieren …

Tand, Tand ist das Gebilde von Menschenhand

Eben so schlimm sind Eigenschaften, die sich ungefragt vererben und nicht “atomar” ein bzw. ausgeschaltet werden können.
Mein liebstes Beispiel sind hier SOCKETs, die mal grundsätzlich an Kindprozesse vererbt werden. Wenn ein Thread Sockets erzeugt, und ein anderer Thread Kindprozesse startet, können wir den Weihnachtsmann fragen, wer welche Geschenke erhalten hat, die er gar nicht haben wollte.

In Linux müssten wir nach dem fork() im Kind “alle” möglichen und unmöglichen Deskriptoren schließen, bevor wir zu exec() kommen dürfen. Und Windows gibt uns zwar SetHandleInformation(), was aber erst nach der Erzeugung eines Sockets aufgerufen werden kann … und da ist es vielleicht auch schon zu spät.

Fazit: Bitte liebe OS-Architekten, bitte unterlasst globale Seiteneffekte.

PS: Und ja, ich weiß dass man Cleanup-Callbacks vor fork() einsetzen kann, und dass es WSA* Routinen gibt, die ein bisschen mehr können. Leider ist trotzdem nicht alles abgedeckt und mal ehrlich … soll sich jetzt jede Ressource in einer “globalen” Liste registrieren und de-registrieren, damit im Falle eines notwendigen Zwischen-Cleanups alles durchgearbeitet werden kann?

Nö! Die Lösung ist alle Seiteneffekte im Vorfeld zu deaktivieren und erst bei Bedarf einschaltbar zu machen … UND NICHT UMGEKEHRT!


Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!