|
|
Leichtgewichtsprozesse: Threads
Relativ neu ist die Möglichkeit, unter UNIX mit Threads zu arbeiten.
Es gab zunächst unterschiedliche Herstellerstandards für die
Programmierschnittstelle von Sun, Unisys und SGI.
Linux definierte einfach Prozesse, die sich Ressourcen teilten und erzeugte
diese Quasi-Threads mit dem Aufruf Threads werden dort eingesetzt, wo parallele Vorgänge benötigt werden, bei denen möglichst wenig Synchronisation erforderlich ist oder in Situationen in denen die parallelen Vorgänge sich viele Ressourcen teilen müssen. Im Gegensatz zu Prozessen teilen sich Threads alle Ressourcen bis auf den Programmzeiger. Das bedeutet, dass die Änderung einer globalen Variablen alle Threads betrifft. Wird der Dateizeiger mit lseek() verändert, ist er für alle Threads verändert. Schließt ein Thread eine Datei, erhält ein paralleler Thread einen Fehler, wenn er auf diese Datei zugreift. Sie müssen auch sicherstellen, dass die Bibliotheken, die Sie benutzen, nicht Probleme mit paralleler Abarbeitung haben. Wer mit Threads arbeiten will, muss also nicht nur die Aufrufe kennen, sondern auch sehr sorgfältig arbeiten. Der Prozess selbst ist immer auch ein Thread. Der Start eines Threads erzeugt also bereits einen zweiten Thread und damit Parallelität. Der Code für diesen zweiten Thread wird als gewöhnliche Funktion geschrieben. Die Funktion wird als Thread gestartet und sobald sie endet, endet auch der Thread. Die Funktion hat einen Zeiger als Parameter. Mit diesem Zeiger können Sie dem Thread beim Start Daten übergeben. Die Thread-Funktion liefert einen Zeiger zurück, mit dem er Daten wieder zurückgeben kann.
Der Aufruf zum Erzeugen eines Threads heißt
#include <pthread.h> int pthread_create(pthread_t *TID, pthread_attr_t *Attribut, void * (*Funktion)(void *), void *Argument);
Der Parameter TID kann man als Thread-ID bezeichnen. Dazu legen Sie eine
Variable vom Typ Der Rückgabewert ist 0, wenn alles in Ordnung ist.
Ein Thread endet, wenn seine Funktion endet. Damit verhält er sich ähnlich
wie die Funktion
#include <pthread.h> void pthread_exit(void *Rueckgabe);
Im Gegensatz zu
Diesen Zeiger bekommt derjenige Thread, der mit Hilfe der Funktion
#include <pthread.h> int pthread_join(pthread_t TID, void **Rueckgabe);
Die Funktion
Das folgende Beispiel startet drei Threads. Die Funktion threadPlus enthält
den Code für jeden Thread. Der Thread bekommt beim Aufruf einen Namen als
Parameter. Dann läuft er in eine Schleife, die endet, wenn die Variable
stopp auf einen Wert ungleich 0 gesetzt wird.
Damit wird die Variable zur Endebedingung für alle Threads.
Innerhalb des Threads wird die globale Variable
Wert erhöht
wenn der Name des Threads mit dem Buchstaben A beginnt, ansonsten wird
der Inhalt der Variablen erniedrigt.
[Multithreading] #include <pthread.h> #include <stdlib.h> #include <unistd.h>
int stopp = 0; /* Synchronisation */ int Wert = 0; /* Globale Variable */
void *threadPlus(void *Arg) { /* Uebergeben wird der Name */ char *Name = (char *)Arg; int diff; /* Differenz fuer Wertberechnung */
if (Name[0]=='A') { diff=1; } else { diff=-1; }
for (;;) { if (stopp) break; /* Thread endet durch Setzen von stopp */ printf("%s: %dn", Name, Wert); /* Namen bestimmt, was der Thread tut */ Wert += diff; sleep(1); } return NULL; }
int main(void) {
pthread_t Add1, Add2, Minus1;
/* Erzeuge und starte drei Threads */ pthread_create(&Add1, NULL, threadPlus, "Add1"); pthread_create(&Add2, NULL, threadPlus, "Add2"); pthread_create(&Minus1, NULL, threadPlus, "Minus1"); sleep(20); /* lass die Threads arbeiten */ stopp = 1; /* beende das Treiben */ /* Warte auf das Ende der Threads und loese sie auf */ pthread_join(Add1, NULL ); pthread_join(Add2, NULL ); pthread_join(Minus1, NULL ); return 0; }
Die drei Threads bekommen jede ihre eigene Thread-ID. Sie werden im
Hauptprogramm gestartet. Der Hauptthread legt sich dann für 20 Sekunden
schlafen und lässt die Threads addieren und subtrahieren. Durch das
Setzen der Variablen Beim Ablauf des Programms erscheint meist Add1, dann Add2 und Minus1 in der normalen Reihenfolge. Man kann aber auch sehen, dass die Reihenfolge wechselt. An der Variablen Wert können Sie erkennen, dass die Veränderung des Wertes davon abhängt, wer gerade an die Reihe kommt. Zum Linken des Programmes muss die Option -lpthread an den Compileraufruf angehängt werden.
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|