Homepage    Computer-Stoff(Titelseite)   Threads(Titelseite)

Was sind Threads?


Threads und Prozesse

Bei vielen Programmierprojekten gibt es Aufgaben, die gleichzeitig erfüllt werden müssen, oder bei denen dies zumindest günstig ist: Server müssen mehrere Anfragen gleichzeitig bearbeiten können; die numerische Verarbeitung von großen Datenmengen kann auf Mehrprozessor-Maschinen schneller geschehen, wenn beide Prozessoren unabhängig voneinander arbeiten; usw.. Eine auf Unix-Systemen mögliche Lösung ist es, die Aufgaben von unterschiedlichen Prozessen erledigen zu lassen, die via Pipes oder shared memory miteinander kommunizieren und Daten austauschen. Jeder Prozeß hat einen eigenen PC (program counter), ein eigenes Code-Segment und einen eigenen Stack.

Threads könnte man als "leightweight processes" bezeichnen. Ein Thread ist ungefähr so wie ein Prozeß, der sein Codesegment -also das eigentlich im Speicher liegende Programm- mit anderen Threads teilt, dieses aber unabhängig von den anderen durchläuft (einen eigenen PC hat) und seinen eigenen Stack und damit insbesondere seine eigenen lokalen Variablen hat. Es ist also so, als ob mehrere Prozesse im gleichen Programm laufen. Jeder dieser bekommt seine eigenen lokalen Variablen, während statische Variablen für alle gültig sind.


Vorteile und Nachteile von Threads

Threads haben also gegenüber eigenen Prozessen den Vorteil, daß sie leichter miteinander kommunizieren können, da sie auf dieselben globalen oder statischen Variablen zugreifen können.

Threads zu erzeugen ist für das Betriebssystem auch lange nicht so aufwendig, wie Prozesse zu duplizieren, da nicht der gesamte Namespace kopiert werden muß. Deshalb sind sie oft wesentlich performanter als einzelne Prozesse.

Dafür sind Threads etwas schwieriger zu programmieren: Wenn man nicht aufpaßt kann es passieren, daß sich zwei Threads eine statische Variable gegenseitig überschreiben, wodurch ein unkorrekter Zustand entsteht, oder daß sich zwei Threads gegenseitig blockieren. Auch beim Debuggen bereiten Programme mit mehreren Threads Schwierigkeiten, da viele Probleme nicht entstehen, wenn man einen Thread anhält, die anderen aber weiterlaufen läßt: Die Fehler treten in einem Debugger einfach nicht mehr auf.


Kernel-Threads und User-Threads

Es gibt zwei Arten von Thread-Implementierungen. Bei Kernel-Threads wird das Scheduling des Betriebssystems verwendet, wodurch beispielsweise zwei Threads auf einem Multiprozessor-System auch tatsächlich in zwei verschiedenen Prozessoren laufen. Bei User-Threads dagegen muß die Library die gesamte Funktionalität bereitstellen. Ich gehe hier nicht weiter auf den Unterschied ein.


LinuxThreads

Um Kernel-Threads zu verwenden, müssen sie vom Betriebssystem unterstützt werden. Für Unix-Systeme gibt es den Posix-Threads-Standard (POSIX 1003.1c-1995), der inzwischen im wesentlichen von allen Unix-Systemen unterstützt wird. Für Linux gibt es die LinuxThreads (libpthread) von Xavier Leroy, eine Implementierung von Kernel-Threads.

Unter Linux werden neue Threads genauso wie neue Prozesse erzeugt. Sie bekommen auch eigene PIDs, so daß mit einem ps-Befehl alle aktuell laufenden Threads angezeigt werden. Bei ihrer Erzeugung im Kernel werden ihnen lediglich andere Eigenschaften als eigenständigen Prozessen zugeteilt. Es ist wichtig, im Hinterkopf zu behalten, daß trotzdem alle Threads in ein und demselben Prozeß laufen. Dies spielt beispielsweise bei der Behandlung von Signalen Rolle.


Thread-Safety

Da alle Threads eines Prozesses auf dasselbe Datensegment zugreifen und in dieses schreiben können, kann es sehr leicht passieren, daß sie sich gegenseitig behindern, indem sie sich die Werte ihrer Variablen gegenseitig verändern, oder indem ein Thread Speicher freigibt, den ein anderer Thread noch braucht, oder ähnliches. Wie man dies verhindert, wird ausführlicher in der Datei über die Synchronisation von Threads besprochen.

Im Allgemeinen reicht es, auf den Gebrauch von statischen und globalen Variablen, sowie auf das Versenden von Signalen an Prozesse, in denen mehrere Threads laufen, zu verzichten.

Die Fähigkeit einer Funktion oder einer Library, immer noch zu funktionieren, wenn sie von mehreren Threads gleichzeitig durchlaufen wird, nennt man "Thread-Safety". Die Funktion heißt dann "thread-safe". Wenn man Anwendungen mit mehreren Threads schreibt, muß man natürlich nicht nur seinen eigenen Code thread-safe gestalten, sondern auch darauf achten, daß die von einem verwendeten Libraries thread-safe sind.


Die Standard-C-Library

Die Standard-C-Library gilt ab der Version glibc2.0 (=libc6.0) als vollkommen thread-safe. Die Versionen davor waren allerdings auch schon ziemlich sicher.

Natürlich gilt dies in keinem Fall für Funktionen, die statische Werte zurückliefern (beispielsweise readdir oder asctime, oder für Funktionen, die aufgrund ihrer Funktion statische Variablen benutzen müssen (z.B. strtok). Für diese Funktionen gibt es aber Ersatz. Diese Ersatz-Funktionen haben denselben Namen, enden allerdings mit einem zusätzlichen _r.

Vergl. den Abschnitt über das Übersetzen von Programmen, die Threads benutzen.


Homepage   Computer-Stoff(Titelseite)   Threads(Titelseite) by Michael Becker, 6/2001 Letzte Änderung: 12/2002.