POSIX Threads (pthreads)
POSIX Threads (pthreads)
POSIX Threads (kurz: pthreads) sind eine standardisierte Programmierschnittstelle zur Verwendung von Threads in Unix-ähnlichen Betriebssystemen (Linux, macOS, BSD, etc.). Sie sind in der **POSIX-Norm (IEEE 1003.1c)** definiert und bilden die Grundlage für Multithreading in der Programmiersprache C auf diesen Systemen.
---
Grundprinzip
Ein **Thread** ist ein leichtgewichtiger Ausführungspfad innerhalb eines Prozesses. Alle Threads eines Prozesses:
- teilen sich den **Adressraum** (Variablen, Speicher, offene Dateien),
- besitzen aber jeweils einen eigenen **Stack** und **Befehlszähler**.
+-----------------------------+ | Prozess | |-----------------------------| | Code, Daten, Heap, Files | |-----------------------------| | Thread 1 → Stack1 | | Thread 2 → Stack2 | | Thread 3 → Stack3 | +-----------------------------+
→ Dadurch sind Threads effizienter als separate Prozesse, aber erfordern sorgfältige Synchronisation.
---
Header-Datei
Alle pthread-Funktionen sind in der Header-Datei enthalten:
#include <pthread.h>
Beim Kompilieren muss oft die pthread-Bibliothek explizit eingebunden werden:
gcc main.c -o main -pthread
---
Wichtige pthread-Funktionen
| Funktion | Beschreibung |
|---|---|
pthread_create() |
Erzeugt einen neuen Thread |
pthread_exit() |
Beendet den aktuellen Thread |
pthread_join() |
Wartet auf die Beendigung eines anderen Threads |
pthread_detach() |
Trennt Thread (keine join-Wartung mehr möglich) |
pthread_self() |
Liefert ID des aktuellen Threads |
pthread_mutex_init() |
Initialisiert einen Mutex (Sperre) |
pthread_mutex_lock() |
Sperrt kritischen Bereich |
pthread_mutex_unlock() |
Gibt Sperre frei |
pthread_cond_wait() / pthread_cond_signal() |
Bedingungsvariablen zur Synchronisation |
---
Beispiel: Einfacher Thread
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* thread_func(void* arg) {
int id = *(int*)arg;
printf("Thread %d läuft!\n", id);
pthread_exit(NULL);
}
int main() {
pthread_t thread;
int id = 1;
// Thread erzeugen
if (pthread_create(&thread, NULL, thread_func, &id) != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
// Warten, bis Thread fertig ist
pthread_join(thread, NULL);
printf("Thread beendet.\n");
return 0;
}
Ergebnis:
Thread 1 läuft! Thread beendet.
---
Beispiel: Mehrere Threads
#include <stdio.h>
#include <pthread.h>
#define N 5
void* worker(void* arg) {
int i = *(int*)arg;
printf("Thread %d: Hallo!\n", i);
return NULL;
}
int main() {
pthread_t threads[N];
int ids[N];
for (int i = 0; i < N; i++) {
ids[i] = i + 1;
pthread_create(&threads[i], NULL, worker, &ids[i]);
}
for (int i = 0; i < N; i++) {
pthread_join(threads[i], NULL);
}
printf("Alle Threads beendet.\n");
return 0;
}
---
Synchronisation mit Mutex
Da Threads denselben Speicher teilen, können sie gleichzeitig auf dieselben Variablen zugreifen → **Race Conditions**. Ein Mutex (Mutual Exclusion Lock) schützt kritische Abschnitte.
#include <stdio.h>
#include <pthread.h>
int counter = 0;
pthread_mutex_t lock;
void* increment(void* arg) {
for (int i = 0; i < 100000; i++) {
pthread_mutex_lock(&lock);
counter++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_mutex_init(&lock, NULL);
pthread_create(&t1, NULL, increment, NULL);
pthread_create(&t2, NULL, increment, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&lock);
printf("Endergebnis: %d\n", counter);
return 0;
}
Ohne Mutex wäre das Ergebnis unbestimmt, weil beide Threads gleichzeitig auf `counter` zugreifen würden.
---
Bedingungsvariablen
Mit pthread_cond_t lassen sich Threads blockieren, bis ein bestimmtes Ereignis eintritt. Das funktioniert immer in Kombination mit einem Mutex.
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;
void* worker(void* arg) {
pthread_mutex_lock(&lock);
while (!ready) {
pthread_cond_wait(&cond, &lock); // wartet auf Signal
}
printf("Thread wurde aktiviert!\n");
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
pthread_t t;
pthread_create(&t, NULL, worker, NULL);
sleep(2);
pthread_mutex_lock(&lock);
ready = 1;
pthread_cond_signal(&cond); // weckt Thread
pthread_mutex_unlock(&lock);
pthread_join(t, NULL);
return 0;
}
---
Thread-Attribute
Mit pthread_attr_t lassen sich Threads konfigurieren:
- Detach-State (joinable/detached)
- Stackgröße
- Scheduling-Parameter
Beispiel:
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&thread, &attr, func, NULL);
pthread_attr_destroy(&attr);
---
Detached Threads
Ein „detached“ Thread kann nicht mehr per pthread_join() abgefragt werden – er gibt seine Ressourcen beim Ende automatisch frei.
Das ist nützlich für kurzlebige Hintergrundaufgaben.
---
Thread-Sicherheit und Reentranz
- Thread-safe Funktionen dürfen von mehreren Threads gleichzeitig genutzt werden (z. B. `printf()` meist sicher).
- Reentrant Funktionen verändern keine globalen Zustände und können unterbrochen werden.
Bei Bedarf stehen sichere Varianten zur Verfügung, z. B.:
strtok_r(), asctime_r() usw.
---
Vor- und Nachteile von POSIX Threads
| Vorteile | Nachteile |
|---|---|
| Hohe Parallelität auf Mehrkernsystemen | Aufwendige Synchronisation |
| Geringer Overhead gegenüber Prozessen | Potenzielle Race Conditions |
| Gemeinsamer Speicher erleichtert Datenaustausch | Fehler schwer zu debuggen |
| Standardisiert (POSIX-konform) | Nicht auf allen Plattformen verfügbar (z. B. Windows ≠ pthreads) |
---
Vergleich zu Prozessen
| Merkmal | Thread | Prozess |
|---|---|---|
| Speicherraum | geteilt | getrennt |
| Startkosten | gering | hoch |
| Kommunikation | direkt über Speicher | über Pipes/Sockets |
| Stabilität | kann andere Threads abstürzen lassen | isoliert |
---
Typische Fehler
- Vergessen, `pthread_join()` aufzurufen (führt zu Zombie-Threads)
- Zugriff auf gemeinsame Daten ohne Mutex
- Nicht initialisierte Synchronisationsobjekte
- Rückgabewerte der pthread-Funktionen ignorieren
---
Siehe auch
- Multithreading
- Race Condition
- Mutex (Programmierung)
- Semaphore
- POSIX (Portable Operating System Interface)
- Operating System (Betriebssystem)
---
Quellen
- IEEE Std 1003.1c-1995 – POSIX Threads (pthreads)
- David R. Butenhof: Programming with POSIX Threads, Addison-Wesley 1997
- Stevens, W. Richard: Advanced Programming in the UNIX Environment, Prentice Hall
- Linux man pages:
man pthread_create,man pthread_mutex_lock - GNU C Library Documentation