Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 10 Threads
  gp 10.1 Unterschiede zwischen Threads und Prozessen
  gp 10.2 Thread-Bibliotheken
  gp 10.3 Kernel- und User-Threads
  gp 10.4 Scheduling und Zustände von Threads
  gp 10.5 Die grundlegenden Funktionen zur Thread–Programmierung
    gp 10.5.1 pthread_create – einen neuen Thread erzeugen
    gp 10.5.2 pthread_exit – einen Thread beenden
    gp 10.5.3 pthread_join – auf das Ende eines Threads warten
    gp 10.5.4 pthread_self – die ID von Threads ermitteln
    gp 10.5.5 pthread_equal – die ID von zwei Threads vergleichen
    gp 10.5.6 pthread_detach – einen Thread unabhängig machen
  gp 10.6 Die Attribute von Threads und das Scheduling
  gp 10.7 Threads synchronisieren
    gp 10.7.1 Mutexe
    gp 10.7.2 Condition-Variablen (Bedingungsvariablen)
    gp 10.7.3 Semaphore
    gp 10.7.4 Weitere Synchronisationstechniken im Überblick
  gp 10.8 Threads abbrechen (canceln)
  gp 10.9 Erzeugen von Thread-spezifischen Daten (TSD-Data)
  gp 10.10 pthread_once – Codeabschnitt einmal ausführen
  gp 10.11 Thread-safe (thread-sichere Funktionen)
  gp 10.12 Threads und Signale
  gp 10.13 Zusammenfassung und Ausblick


Rheinwerk Computing

10.9 Erzeugen von Thread-spezifischen Daten (TSD-Datatoptop

Bei einem Aufruf von Funktionen werden die lokalen Daten auf dem Stack abgelegt und auch wieder abgeholt. Bei den Threads kann man ja solch langlebige Daten entweder mit zusätzlichen Argumenten an die einzelnen Threads weitergeben oder aber in globalen Variablen speichern. Wenn Sie aber z. B. vorhaben, eine Bibliothek für den Multithread-Gebrauch zu schreiben, ist dies nicht mehr möglich, da man ja hierbei die Argumentzahl nicht mehr verändern kann, damit auch ältere Programme ohne Threads diese Bibliothek verwenden können und man auch nicht weiß, wie viele Threads die Bibliotheksfunktionen nutzen werden, kann man nun mal keine Aussage darüber machen, wie groß die globalen Daten sein sollen.

Das Ganze vielleicht noch etwas vereinfacht erklärt, es ist einfach nicht möglich, dass globale und statische Variablen unterschiedliche Werte in den verschiedenen Threads haben können. Aus diesem Grund wurden »Schlüssel« eingeführt - oder auch Thread-spezifische Daten (kurz TSD-Data). Dabei handelt es sich um eine Art Zeiger, der immer auf die Daten verweist, die dem Thread gehören, der eben einen entsprechenden »Schlüssel« benutzt. Beachten Sie allerdings, dass hierbei immer mehrere Threads den gleichen »Schlüssel« benutzen – nicht jeder Thread einen extra »Schlüssel«!

Dabei bekommt jeder Thread einen privaten Speicherbereich mit einem eigenen Schlüssel zugeteilt. Dies kann man sich gerne als ein Array von void-Zeigern vorstellen, auf die der Thread mit »seinem« Schlüssel zugreifen kann.

Hierzu die Funktionen, womit Sie Thread-spezifische Daten erzeugen bzw. die damit arbeiten können.

#include <pthread. h.>
int pthread_key_create( 
   pthread_key_t *key, void (*destr_function) (void*) );
int pthread_key_delete( pthread_key_t key );
int pthread_setspecific(
   pthread_key_t key, const void *pointer );
void * pthread_getspecific(pthread_key_t key);

Mit pthread_key_create() erzeugen Sie einen neuen TSD-Schlüssel mit der Speicherstelle key des Schlüssels und (als zweites Argument) entweder NULL oder die Funktion, um den Speicher der Daten wieder freizugeben, eine Exit-Handler-Funktion, wenn Sie so wollen.

Mit der Funktion pthread_setspecific() können Sie Daten mit dem TSD-Schlüssel assoziieren. Sie legen damit praktisch die TSD-Daten für den TSD-Schlüssel key über den Zeiger pointer fest.

Mit der Funktion pthread_getspecific() kann man die Daten aus dem TSD-Schlüssel auslesen.

Mit dem folgenden Beispiel werden MAX_THREADS Threads erzeugt, von denen jeder Thread eine Thread-eigene Datei mittels TDS-Daten erzeugt. Im Beispiel wird hierbei nur protokolliert, dass der Thread gestartet und wieder beendet wurde. Zwischen den beiden Zeilen sollten Sie die eigentliche Arbeit des Threads eintragen. Fehler oder sonstige Meldungen dieser Arbeit können Sie ebenfalls wieder mit »thread_write« in die für den Thread vorgesehene Datei schreiben. Dass diese Funktion »nur« mit einem einfachen String aufgerufen werden kann, ist dem TSD-Schlüssel zu verdanken, der in der Funktion »thread_write« mittels pthread_getspecific() eingelesen wird. Ein simples Grundgerüst eben, womit Sie ohne großen Aufwand Thread-eigene Logdateien verwenden können.

/* thread17.c */
#include <pthread. h.>
#include <stdio.h>
#include <stdlib.h>
#define MAX_THREADS 3
/* TSD-Datenschlüssel */
static pthread_key_t tsd_key;
/* Schreibt einen Text in eine Datei für 
 * jeden aktuellen Thread */
void thread_write (const char* text) {
  /* TSD-Daten lesen */
  FILE* th_fp = (FILE*) pthread_getspecific (tsd_key);
  fprintf (th_fp, "%s\n", text);
}
/* Am Ende den Zeiger auf die Datei(en) schließen */
void thread_close (void* th_fp) {
  fclose ((FILE*) th_fp);
}
void* thread_tsd (void* args) {
  char th_fpname[20];
  FILE* th_fp;
  /* Einen Thread-spezifischen Dateinamen erzeugen */
  sprintf(th_fpname,"thread%d.thread",(int) pthread_self());
  /* Die Datei öffnen  */
  th_fp = fopen (th_fpname, "w");
  if( th_fp == NULL )
    pthread_exit(NULL);
  /* TSD-Daten zu TSD-Schlüssel festlegen */
  pthread_setspecific (tsd_key, th_fp);
  thread_write ("Thread wurde gestartet ...\n");
  
  /* Hier kommt die eigentliche Arbeit des Threads hin */
  thread_write("Thread ist fertig ...\n");
  pthread_exit(NULL);
}
int main (void) {
  int i;
  pthread_t threads[MAX_THREADS];
  /* Einen neuen TSD-Schlüssel erzeugen - Beim Ende eines 
   * Threads wird die Funktion thread_close ausgeführt   */
  pthread_key_create (&tsd_key, thread_close);
  /* Threads erzeugen */
  for (i = 0; i < MAX_THREADS; ++i)
    pthread_create (&(threads[i]), NULL, thread_tsd, NULL);
  /* Auf die Threads warten  */
  for (i = 0; i < MAX_THREADS; ++i)
    pthread_join (threads[i], NULL);
  return EXIT_SUCCESS;
}

Das Programm bei der Ausführung:

$ gcc -o thread17 thread17.c -lpthread
$ ./thread17
$ ls *.thread
thread-1209418832.thread  thread-1217811536.thread  thread-1226204240.thread
$ cat thread-1209418832.thread
Thread wurde gestartet ...
Thread ist fertig ...
 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern