Suchen
Verloren im Labyrinth der IT-Begriffe? Hier finden Sie Definitionen und Basiswissen zu Rechenzentrums-IT und -Infrastruktur.

Tipps, damit der Code nicht am seidenen Faden hängt Was sind Threads und was bringen sie?

Autor / Redakteur: M.A. Jürgen Höfling / Ulrike Ostler

Nebenläufige Programmfäden (Threads) gehören heute zu den Standard-Instrumenten in der Programm-Entwicklung, um Aufgabenstellungen zu strukturieren und zu parallelisieren. Dabei sind einige Regeln zu beachten, damit die theoretischen Vorteile in der Praxis wirken.

Firma zum Thema

Die Einteilung eines Prozesses in einzelne Programmfäden (Threads) gehört heute zu den Basics der Programmierung.
Die Einteilung eines Prozesses in einzelne Programmfäden (Threads) gehört heute zu den Basics der Programmierung.
(Bild: Uschi_Dreiucker_pixelio.de)

Auch in der IT wird immer feiner gesponnen, will heißen: Modernes Hochleistungsrechnen wäre ohne die Multi-Kern / Multi-Prozessor-Technologie mit ihren „nebenläufigen Programmfäden“ (Threads) innerhalb eines Prozesses kaum denkbar. Mittlerweile gibt es schon CPU-Bausteine mit 64 Kernen und 128 Threads, zum Beispiel der Prozessor der „AMD Epyc 7742“. Die Kerne arbeiten dabei ihre jeweiligen Tasks simultan ab und zusätzlich wechselt jeder Kern noch zwischen zwei Threads so schnell hin und her, dass es wie Parallelverarbeitung aussieht.

Kommunikation „auf dem kurzen Dienstweg“

Aufgaben jedweder Art, ob in der Schule, im Büro, in der Werkshalle oder im Forschungslabor, können in der Regel auf eine immer gleiche abstrakte Struktur zurückgeführt werden: Sie lassen sich in einen Hauptstrang und mehrere (viele?) Nebenstränge unterteilen, sozusagen die „Nebenrechnungen“, die für die Bewältigung der Hauptaufgabe notwendig sind. In der „Alltags-Computerei“ ist beispielsweise die Textverarbeitung insgesamt ein Prozess, und das, was sich bei Word hinter den Registerkarten versteckt (Ein- Ausgabe-Operationen, Rechtschreibprüfung oder automatisches Speichern) kann in Threads untergebracht werden.

Ganz offensichtlich setzen diese Programmfäden auf Aktionen und Daten des Texteditors auf, insofern wäre es wenig sinnvoll, wenn auch durchaus möglich, diese Unterprozesse jeweils als eigenen Prozess zu definieren. Denn ein Prozess-Wechsel kostet im Vergleich zu einem Thread-Wechsel durchschnittlich das Hundert- bis Tausendfache an Rechenzeit, weil beispielsweise die Prozess-Register umgeschrieben werden müssen.

Threads hingegen stützen sich auf die Betriebsmittel des Prozesses ab, dem sie zugeordnet sind. Sie haben zwar einen eigenen Befehlszähler, einen unabhängigen Registersatz und einen eigenen Stapelspeicher (Stack), aber das alles in der Regel im Prozess-Adressraum. Dadurch kann die Kommunikation zwischen den Programmfäden auf dem kurzen Dienstweg erledigt werden, also schnell und einfach.

Threads erhöhen Programmier-Komplexität

Da die meisten der Betriebsmittel eines Prozesses von dessen Threads gemeinsam verwendet werden, sollte tunlichst auf potenzielle Zugriffskonflikte geachtet werden und es sollten daraus entstehende Konflikte durch geeignete Mechanismen entschärft beziehungsweise möglichst schon im Vorfeld erkannt und aufgelöst werden. Wenn die vorausschauende Konfliktauflösung nicht ordentlich funktioniert, kann es im Extremfall dazu kommen, dass sich mehrere Threads eines Prozesses um ein Betriebsmittel streiten müssen und sich dabei wechselseitig blockieren („Deadlock“).

Wenn Kommunikationsmechanismen versagen, weil ungeschickt programmiert worden ist, kann ein Thread auch in eine Endlos-Schleife geraten („Livelock“). Das ist dann ein bisschen so, wie wenn Wasser ins Boot läuft und die Besatzung nur durch stetiges Wasserschöpfen verhindern kann, dass sie absäuft. Man ist zwar nicht tot, aber ein gutes Leben sieht anders aus. Eine nachhaltige Lösung ist das jedenfalls nicht, weder in der Aqua-Touristik noch in der Informatik.

Threads arbeiten nicht tatsächlich parallel, sondern nur scheinbar parallel. Das heißt, die Programmwechsel sind so schnell, dass sie im Programmablauf parallel erscheinen. Programmtechnisch wird diese Quasi-Parallelität durch die Vergabe von Time-Slots innerhalb des Gesamtprogramms realisiert. Das bringt aber auch zusätzliche Komplexität in die Programm-Entwicklung mit entsprechenden Fehlermöglichkeiten.

Dummerweise lassen sich nämlich durch die Time-Slots etwaige Programmierfehler oft nur schwer entdecken, da sich bei jedem neuen Programm-Durchlauf die Slots ein bisschen verschieben können. Fehler sind somit aufgrund der nicht deterministischen Abläufe im streng begrifflichen Sinn nicht reproduzierbar.

Threads auf Kernel- und auf Anwender-Ebene

Die hier angedeuteten Einschränkungen und Fallstricke sollten aber nicht überbewertet werden. De facto sind Threads heute eine eingespielte Software-Technik. Praktisch alle heutigen Prozessor-Architekturen setzen Threads voraus. Der zu Anfang beispielhaft erwähnte CPU-Baustein mit 64 Kernen und 128 Threads zeigt deutlich, welche große Breite an Parallel- und Quasi-Parallelverarbeitung heute möglich ist und programmtechnisch effektiv und vor allem auch effizient genutzt wird. Aber klar ist auch: der Software-Entwickler sollte über solide Kenntnisse der Thread-Programmierung verfügen, um die Vorteile auch wirklich ausnutzen zu können.

Die gängigen Betriebssysteme unterstützen heute die Nutzung von Threads, und zwar vor allem auch in dem Sinn, dass sie die Verwaltung der Programmfäden übernehmen. Es existiert dann eine integrierte Thread-Steuerung, ganz ähnlich der Prozess-Steuerung. Falls das Betriebssystem keine Threads direkt unterstützt, ist eine Thread-Programmierung auf Kernel-Ebene nicht möglich, wohl aber auf Anwender-Ebene über verschiedene Anwender-Programmier-Schnittstellen (API), die das Betriebssystem zur Verfügung stellt.

So implementiert beispielsweise die Java-Laufzeit-Umgebung (Java Runtime Environment, JVE) eine eigne Thread-Verwaltung, auf die zurückgegriffen werden kann, falls das zugrunde liegende Betriebssystem „fadenscheinig“ ist, also keine Threads unterstützt. Falls JVE mit einem thread-affinen Betriebssystem betrieben wird, kann sich der Programmierer aussuchen, ob er oder sie die Fäden auf Kernel- oder auf User-Ebene ziehen wollen. Auf dass der Code stabil, sicher und effizient ist und nichts am sprichwörtlichen seidenen Faden hängt.

(ID:46949659)

Über den Autor