Sehr Umfangreiche Webseite zum Programmieren in C Perl CGI, Skripting, Linux, Systemprogrammierung C C++ C/C++ ANSI C Linux Linuxsystemprogrammierung Parallele Programmierung Threads Linuxsystemprogrammieren Parallele Programmierung Threads 8. Parallele Programmierung mit Threads

8.6. Threads canceln           zurück zum Inhaltsverzeichnis

Kommen wir nun zu weiteren nützlichen Threadfunktionen. Zur Beendigung einzelner Threads, außer mit return oder pthread_exit, gibt es noch die folgende Funktion ...

int pthread_cancel(phtread_t thread);

Hiermit wird der Thread mit der ID von thread beendet, abhängig von folgenden Punkten ...

Abbruchstatus
Die Default-Einstellung dieses Statuses ist PTHREAD_CANCEL_ENABLE, was bedeutet, dass der Abbruch des Threads aus einem zweiten Thread erlaubt ist. Wenn Sie die Konstante PTHREAD_CANCEL_DISABLE setzen, unterbinden Sie dies. Setzen können Sie diese beiden Konstanten mit der Funktion ...

int pthread_setcancelstate(int state, int *oldstate);

Sehen Sie sich das Ganze mal in der Praxis an ...

#include <stdio.h>
#include <pthread.h>
#include <asm/errno.h>
#include <stdlib.h>
#include <time.h>

pthread_t t1,t2,t3;
int zufallszahl;

void cancel_test1()
{
  if(zufallszahl>25)
   {
     pthread_cancel(t3);
     printf("%d : Habe \"THREAD2\" beendet!\n",zufallszahl);
   }
  printf("TREAD1 zuende\n");
  pthread_exit((void*)0);
}

void cancel_test2()
{
  if(zufallszahl<=25)
   {
     pthread_cancel(t2);
     printf("%d : Habe \"THREAD1\" beendet!\n",zufallszahl);
   }
  printf("THREAD2 zuende\n");
  pthread_exit((void*)0);
}


void zufall(void)
{
  srand(time(NULL));
  zufallszahl=rand()%50;
  pthread_exit(NULL);
}



int main()
{
  if((pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) !=0)
   {
      fprintf(stderr,"Fehler bei pthread_setcancelstate.......\n");
      exit(0);
   }

  if((pthread_create(&t1, NULL, (void *)&zufall, NULL)) !=0)
    {
       fprintf(stderr, "Fehler bei ptread_create.........\n");
       exit(0);
    }

  if((pthread_create(&t2, NULL, (void *)&cancel_test1, NULL)) !=0)
    {
      fprintf(stderr, "Fehler bei ptread_create.........\n");
      exit(0);
    }

  if((pthread_create(&t3, NULL, (void *)&cancel_test2, NULL)) !=0)
    {
      fprintf(stderr, "Fehler bei ptread_create.........\n");
      exit(0);
    }

  return 0;
}

Wir erzeugen hier drei Threads. Einer erzeugt eine Zufallszahl, die anderen zwei Threads reagieren entsprechend auf diese Zufallszahl. Je nach dem, ob die Zufallszahl kleiner bzw. größer als 25 ist, beendet der eine Thread den anderen mit pthread_cancel. Wenn Sie das Programm ausführen, wird trotzdem nach Beendigung einer der beiden Threads mit pthread_cancel, zweimal ausgegeben ...

Threadn beendet

Wie kann das sein, wo Sie doch mindestens einen Thread beendet haben? Das ist die zweite Bedingung zur Beendigung von Threads. Nämlich die Reaktion auf die Abbruchsanforderungen. Die Default-Einstellung lautet hier nämlich PTHREAD_CANCEL_DEFERRED. Damit läuft der Thread noch einmal bis zum nächsten Abbruchspunkt. In unserem Fall pthread_exit. Wenn Sie einen Thread sofort abbrechen wollen bzw. müssen, benötigen Sie die Konstante PTHREAD_CANCEL_ASYNCHRONOUS. Diese beiden Konstanten können Sie mit der Funktion ...

int pthread_setcanceltype(int type, int *oldtype);

...setzen. Wollen wir das wieder in unser Programm einbauen...

if((pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) != 0)
{
  fprintf(stderr, "Fehler bei pthread_setcanceltype..........\n");
  exit(0);
}

Schreiben Sie dies in die main-Funktion. Ich muss Anmerken, dass diese Funktion pthread_setcanceltype, sobald wie möglich abbricht. Aus diesem Grund kann es schon passieren, dass in unserem Beispiel dennoch beide Funktionen bis zum Schluss ausgeführt werden. Wollen wir uns noch ein Beispiel zu pthread_cancel ansehen.

Doch zuvor kommen wir noch schnell zur Fehlerbehandlung von Threads. Alle Threadfunktionen geben, falls sie ohne Fehler gelaufen sind, 0 zurück. Ansonsten einen positiven Wert aber niemals -1. Also könnten Sie eine Funktion definieren, die für alle Threads gültig ist. Auf der Suche im Internet zu den Threads habe ich dabei folgende Funktion gefunden ...

void checkResults(string, val) {
    if (val) {
      printf("Failed with %d at %s", val, string);
      exit(1);
    }
}

Nehmen wir gleich nochmals das Beispiel zuvor zum Testen dieser Funktion ...

int status;
..............
status=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
checkResults("pthread_setcancelstate()",status);

Dies sieht doch schon besser aus, oder? Die Funktion wird auch nur Ausgeführt, wenn der status ungleich 0 ist, also bei Fehler. Hier nun das komplette Beispiel dazu ...

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/*Fehlerbeendigung für alle Threads*/
void checkResults(string, val) {
    if (val) {
      printf("Failed with %d at %s", val, string);
      exit(1);
    }
}

void *theThread(void *parm)
{
  printf("Thread: Anfang\n");
  while (1) {
     printf("Thread: In der Schleife und wartet auf Anfrage\n");
     pthread_testcancel();
     sleep(1);
                   }
  return NULL;
}

int main(int argc, char **argv)
{
  pthread_t thread;
  int rc=0;
  void *status;

  printf("Beginne Test - %s\n", argv[0]);

  printf("Create/startet einen thread\n");
  rc = pthread_create(&thread, NULL, theThread, NULL);
  checkResults("pthread_create()\n", rc);

  printf("Wir warten ein bißchen bis wir unseren Thread wieder beenden\n");
  sleep(3);
  rc = pthread_cancel(thread);
  checkResults("pthread_cancel()\n", rc);

  printf("Wir warten bis unser Thread fertig ist und die Ressourcen freigibt\n");
  rc = pthread_join(thread, &status);
  checkResults("pthread_join()\n", rc);

  printf("Thread zeigt an das er fertig ist\n");
  if (status != PTHREAD_CANCELED) {
           printf("Unexpected thread status\n");
           }

  printf("Main completed\n");
  return 0;
}

Das Programm dürfte eigentlich selbsterklärend und nicht schwer zu verstehen sein.

Signale und Threads
Das das Signal SIGKILL alle Threads auf einmal beendet dürfte wohl klar sein. Dies gilt auch für die Funktion ...

int pthread_kill(pthread_t th, int sig);

Wollen Sie einem bestimmten Thread ein Signal senden, können Sie dies mit folgender Funktion machen ...

int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask);

Mehr zu den Signalen und Threads finden sie unter ...

man pthread_kill
man pthread_sigmask
man sigwait

Allgemein empfehle ich Ihnen zu den Threads in der man-Page nachzulesen. Dort finden Sie noch eine Menge mehr dazu.

Dies waren natürlich nicht alle Funktionen zu der Thread-Programmierung mit libpthread. Ich hoffe Ihnen damit etwas zur Threadprogrammierung beigebracht zu haben.

Weiter mit 9.1. Memory Mapped I/O - mmap