ein Kapitel zurück                                           ein Kapitel weiter

Die Threads die sie im Kapitel zuvor mit pthread_create erstellt haben wurden alle mit folgenden default-Eigenschaften erstellt.......

  • unbounded
  • nondetached - Ein Thread bleibt bei Beendigung mit seinem Identifier und seinen Resourcen bestehen. Dies ist auch gut so, denn sonst könnten sie wie im Beispiel des Kapitels zuvor, den Thread nicht mittels pthread_join nach seinem Rückgabewert fragen. Dabei spricht man von nodetached.
  • default Stack und default Stackgröße
  • Die Eigenschaften der "Eltern" (genauer des Prozesses)

Diese Eigenschaften hat der Thread also wenn sie mit pthread_create als 2.Argument den NULL - Zeiger angeben oder mit der Funktion........

int pthread_attr_init(pthread_attr_t *attr);  

Beispielsweise........

pthread_t t1;
pthread_attr_t defaultattr;

pthread_attr_init(&defaultattr);
pthread_create(&t1, &defaultattr, (void *)&Funktion, (void *)"Thread" );  

Damit würden sie dasselbe erreichen wie mit....

pthread_create(&t1, NULL, (void *)&Funktion, (void *)"Thread" );  

Die Attribute werden in der Regel aber recht selten verändert. Trotzdem will ich Sie für den Fall der Fälle etwas rüsten.

Scheduling

Um die Struktur pthread_attr_t zu verstehen will ich den Scheduler in der Thread-Bibliothek kurz erklären. Den ohne diesem Scheduler würden die Threads machen was sie wollen.

Der Scheduler bestimmt wann welcher Thread Prozesszeit erhält zum Arbeiten. Dies kann mit dem Scheduler nach Priorität oder nach Zeit erfolgen. Nach Priorität laufen die einzelnen Threads ab der höchsten bis zur niedrigsten Priorität ab. Bei der Zeit läuft ein Thread eine gewisse Zeit die festgelegt ist und wird dann automatisch unterbrochen.

Da die libpthread-Bibliothek eine Kern-Level-Bibliothek ist und keine User-Level-Bibliothek stehen uns beide Möglichkeiten zur Verfügung.

Bitte bedenken sie wenn sie Threads erstellen die Prioritätsabhängig laufen, das sie dafür Verantwortlich sind wenn ein Thread den Prozessor beansprucht, diese Blockieren auch wieder aufzuheben, damit andere Threads auch zum Zuge kommen können.

Hier nun die Stuktur der Eigenschaften von Threads.....

/*Attribute für Threads in  <bits/pthreadstypes.h>*/

typedef struct __pthread_attr_s
     {
      int __detachstate;
      int __schedpolicy;
      struct __sched_param __schedparam;
      int __inheritsched;
      int __scope;
      size_t __guardsize;
      int __stackaddr_set;
      void *__stackaddr;
      size_t __stacksize;
     } pthread_attr_t;  

Mit den Funktion....

int pthread_detach(pthread_t th);  

...können sie die Variable von __detachstate setzen. Dies bedeutet wenn sie diese Funktion verwenden werden alle Resourcen des Threads sofort freigegeben. Auch der Rückgabewert wird nicht mehr benötigt und ist somit mit pthread_join nicht mehr Abzufragen. Sie verlieren dabei allerdings jede Kontrolle des Threads bis zum Ende.

Sie können Threads aber auch direkt detached erzeugen mit der Funktion.....

int pthread_attr_setdetachstate(pthread_attr_t *attr, int datachestat);  

Für detachstate können dabei folgende Konstanten verwenden......

PTHREAD_CREATE_JOINABLE   /*default-Einstellung bei Erzeugung mit pthread_create*/
PTHREAD_CREATE_DETACHED
  

Im Anwendungsfall sieht dies dann so aus........

/*Download:thread4.c*/
#include <stdio.h> #include <pthread.h> void Funktion(void *arg) { printf("Hallo vom %s\n",(char *)arg); pthread_exit((void *)0); } int main() { pthread_t t1; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&t1, &attr, (void *)&Funktion, (void *)"Thread" ); return 0; }

Sie sollten natürlich den Fehlerfall überprüfen. Außerdem sollten sie (ich nehme mal an das sie nicht nur solch kurzes Snippets erstellen werden) überprüfen, ob Ihr Thread bereits auf detached oder nicht gesetzt wurde. Dies könne sie mit der Funktion....

int pthread_attr_getdetachstate(pthread_attr_t *attr, int *datachestat);  

...erledigen.

Den Scheduler des Threads können sie mit den Funktionen.........

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t *attr, int policy);  

...setzen (set) oder abfragen (get). Folgende Möglichkeiten können sie dabei an policy vergeben......

  • SCHED_OTHER - (default-Einstellung) Mit dieser Einstellung wird der Prozess unterbrochen wenn ein Prozess/Thread mit Höherer Priorität auf seine Ausführung wartet.
  • SCHED_FIFO - Hohe Priorität. Dieser Prozess/Thread kann nur von einem Prozess mit hoher Priorität abgelöst werden oder der Prozess beendet sich selbst. (Nur als root nutzbar)
  • SCHED_RR - Round-Robin-Stratgie. Genau wie SCHED_FIFO, nur kann ein solcher Prozess/Thread von einem mit der gleichen Priorität abgelöst werden (Nur als root nutzbar)

Hierzu natürlich auch ein Anwendungsbeispiel........

/*Download:thread5.c*/
#include <stdio.h> #include <pthread.h> void set_sched(void *name) { pthread_attr_t attr; int ret; int policy; policy = SCHED_OTHER; ret = pthread_attr_setschedpolicy(&attr, policy); if(ret == 0) fprintf(stderr,"Konnte Scheduling nicht auf SCHED_OTHER stellen\n"); printf("Status von %s mit ID %ld : \n",(char *)name,pthread_self()); pthread_exit((void *) 0); } int main() { pthread_t t1, t2; if(pthread_create(&t1, NULL, (void *)&set_sched, (void *)"Thread 1") != 0) { fprintf(stderr, "Fehler bei Thread 1......\n"); exit(0); } if(pthread_create(&t2, NULL, (void *)&set_sched, (void *)"Thread 2") != 0) { fprintf(stderr, "Fehler bei Thread 1......\n"); exit(0); } pthread_join(t2, NULL); /*Wir warten bis Thread2 zu Ende ist*/ return 0; }

Um den Scheduler nun wirklich zu verändern also ob nun Zeit-oder-Prioritätsgesteuert gäbe es die Funktionen.....

int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(pthread_attr_t *attr, int *scope);  

zum Setzen oder Abfragen des Schedulers. Da Linux-Threads als Konstante scope nur PTHREAD_SCOPE_SYSTEM unterstützt ist der Fall trival. Damit wird der Scheduler Zeitgesteuert. Die Konstante PTHREAD_SCOPE_PROCESS wird von Linux Threads nicht unterstützt für Prioritätsorientierte Steuerung.

Mit den beiden Funktionen........

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
int pthread_attr_getinheritsched(pthread_attr_t *attr, int inherit)  

...werden dazu verwenden zum Setzen oder Abfragen ob der Thread die Attribute vom Vater-Thread übernimmt. Dazu können sie der Variablen inherit folgende 2 Konstanten übergeben......

  • PTHREAD_INHERIT_SCHED - Thread übernimmt Attribute von Vaterthread
  • PTHREAD_EXPLICIT_SCHED - Thread übernimmt die Attribute vom Vaterthread nicht

Manchesmal kann es nötig sein nachzufragen um welchen Thread es sich gerade handelt. Wie bei den Prozessen mit der Funktion getpid. In diesem Fall können wir auf die Funktion.......

pthread_t pthread_self(void);  

nachhelfen. Hierzu das Anwendungsbeispiel.........

/*Download:thread6.c*/
#include <stdio.h> #include <pthread.h> void pidof_thread(void *name) { printf("Nachricht von Thread mit der ID %ld\n",pthread_self()); pthread_exit((void *) 0); } int main() { pthread_t th[3]; int i; for(i=0; i<3; i++) { if(pthread_create(&th[i], NULL, (void *)&pidof_thread, (void *)NULL) != 0) { fprintf(stderr, "Fehler beim Erzeugen eines Threads.!?!?!\n"); exit(0); } } for(i=0; i<3; i++); pthread_join(th[i], NULL); return 0; }

Wir erzeugen hier 3 Threads und Fragen in der Funktion pidof_thread deren ID ab. Hier sehen sie eine andere und komfortablere Möglichkeit Threads zu erzeugen und auf den Beendigungsstatus zu warten.

Es ist auch möglich und manchesmal nötig 2 Threads zu vergleichen. Beispielsweise folgende Funktion....

void what_is_it(void *name)
{
  printf("WauWau\n");
  printf("Miau\n");
  pthread_exit((void *) 0);
}  

Sie wollen hier das ein Thread den Hund darstellen soll und ein anderer Thread die Katz. Vergleichen können wir zwei Threads mit der Funktion......

int pthread_equal(pthread th1, pthread th2);  

Die Funktion liefert ungleich 0 zurück wenn beide Threads die selbe ID haben. Hier das ganze in unserer Funktion....

pthread_t th[2];

void what_is_it(void *name)
{
  if(pthread_equal(pthread_self(),th[1]))
    printf("\nThread %ld sagt : WauWau\n",pthread_self());
  if(pthread_equal(pthread_self(),th[0]))
    printf("Thread %ld sagt : Miau\n", pthread_self());
  pthread_exit((void *) 0);
}  

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf