- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 10 von 11

Thema: Frage zu pthread_testcancel();

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    HaWe
    Gast

    Frage zu pthread_testcancel();

    hallo,
    ich bin noch dabei, für den Fall von Notstopp-Events meinen Robot sicher und schnell zum Stehen zu bringen und auch langdauernde Threads sicher und schnell abbrechen zu können.

    Beispielhaft folgendes vereinfachte Setup:

    main() initialisiert 2 pthreads, nämlich threadname1() und threadname2().

    einer davon startet, sobald er aufgerufen wird, eine rekursive Funktion, die sehr viel Rechenzeit erfordert (z.B. einen AStern).
    Code:
    void AStern(int x, int y, int xz, int yz) {
        // tutwas 
        //  ruft sich selber auf
         Astern(x+1, y+1, 100,90);  
    
       // tut wieder was bis zur Abbruchbedingung
    }
    
    void *threadname2 (void *arg) {        
    	printf("starte Astern\n");
            AStern(0,0, 100,90);        
    	return NULL;
    }
    es macht hier sicher nur wenig Sinn, pthread_testcancel() im pthread threadname2() auftzurufen, da ja nach Start sofort die Funktion AStern() angesprungen wird.
    Macht es aber Sinn, in der Funktion AStern() z.B. ganz am Anfang diesen Befehl zu setzen uns ggf. auch im Code zwischendurch auch nochmal, damit öfter (z.B. in jeder rekursiven Instanz) auf Abbruch von threadname2 getestet wird?

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Karlsruhe
    Alter
    36
    Beiträge
    1.225
    Zitat Zitat von HaWe Beitrag anzeigen
    Macht es aber Sinn, in der Funktion AStern() z.B. ganz am Anfang diesen Befehl zu setzen uns ggf. auch im Code zwischendurch auch nochmal, damit öfter (z.B. in jeder rekursiven Instanz) auf Abbruch von threadname2 getestet wird?
    Ja, genau so ist das gedacht. Vielleicht willst du eine Funktion "pollEvents()" o.ä. definieren, die regelmäßig aufgerufen werden soll, und in der du dann pthread_testcancel() ausführst und außerdem noch alles andere was vielleicht so gelegentlich Mal an Ereignissen abgearbeitet werden soll.

    Grüße,
    Markus
    Tiny ASURO Library: Thread und sf.net Seite

  3. #3
    HaWe
    Gast
    prima, danke für die Rückmeldung!
    Ich hatte befürchtet, pthread_testcancel() würde vlt nur direkt in dem pthread-Thread wirken, in dem der extern ausgelöste pthread_cancel() wirken soll, also "direkt" im Funktionskörper von *threadname2 () ,
    evtl aber vlt nicht mehr in nachgeordneten Funktionen, die ihrerseits nur von dem pthread sekundär angesprungen wurden (und vlt ja nicht "wissen" über die pthread-ID, die hier ggf gemeint bzw. betroffen ist, hier in AStern().
    Wie das AStern "merken soll", welcher übergeordnete Thread beendet werden soll (und damit auch AStern selber) ist mir allerdings noch nicht klar - aber gut, wenn es dann wenigstens funktioniert wie geplant

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Karlsruhe
    Alter
    36
    Beiträge
    1.225
    pthread_testcancel() interessiert sich nicht dafür, welche andere Funktion sie aufruft. Jeder Thread hat gewisse Kontextinformationen, und auf diese wird zugegriffen. Du bekommst also immer die Information zu dem Thread der deine Funktion gerade jetzt ausführt. Wenn deine Funktion von zwei Threads ausgeführt wird, kann das Ergebnis also durchaus einmal TRUE und einmal FALSE sein!

    Grüße,
    Markus
    Tiny ASURO Library: Thread und sf.net Seite

  5. #5
    HaWe
    Gast
    neinnein, jede die es betrifft, wird nur 1x von 1 Thread aus angesprungen.
    Ich habe mal eine kleine Simulation geschrieben:

    Einer der Threads startet eine Fibonacci-Berechnung linear (sehr schnell),
    der andere eine andere, rekursive Fibinacci-Funktion (viel langsamer).

    lässt man jetzt die Fibonacci (93) berechnen, ist Thread2-linear schnell fertig (nur zu Simulationszwecken),
    Thread1-rekursiv braucht aber ewig.

    beide Threads können durch einen 3. Thread abgebrochen werden, wenn man ESC drückt (um Thread2-linear zu erwischen, irre schnell ... ).

    Aber egal, ob jetzt in Fibo-Rekursiv ein pthread_testcancel drin steht oder nicht:
    es dauert immer gleich lang bis zum Abbruch des rekursiven , nämlich (bei meinem Linux) ca. 3 sec.

    Eigentlich ist das zu lang, und es müsste auch viel schneller gehen, da sich jede Sekunde mindestens 100x die Funktion selber rekursiv aufruft, und daher theoretisch also auch innerhalb von 10ms abgebrochen werden müsste mit pthread_testcancel() am Anfang eines jeden neuen (rekursiven) Funktionsstarts
    - fast ewig lang allein bis zur Reaktion auf den Abbruch, vergleicht man es mit dem kompletten Durchlauf der gesamten kompletten linearen Funktion bis zur 200. Iteration, erkennbar auch an der ausgegeben printf-ESC-Sequenz im Terminal bis zur letztendlichen Abbruch-Reaktion.

    Sehr effektiv, gelinde gesagt, scheint also pthread_testcancel in der "abhängigen" rekursiven Funktion nicht zu wirken...
    Code:
    /*
     *  Fibonacci numbers
     *  simulaneous competition:
     *  linear vs. recursive calculation
     * 
     */
    
    
    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <termio.h>
    
    #define msleep(ms)  usleep(1000*ms)
    
    pthread_t threadID0, threadID1, threadID2;
    
    long f;
    
    volatile int running1 = 1;
    volatile int running2 = 1;
    
    
    // ********************************************************************
    
    
    bool kbhit(void)
    {
        struct termios original;
        tcgetattr(STDIN_FILENO, &original);
    
        struct termios term;
        memcpy(&term, &original, sizeof(term));
        term.c_lflag &= ~ICANON;
        tcsetattr(STDIN_FILENO, TCSANOW, &term);
    
        int characters_buffered = 0;
        ioctl(STDIN_FILENO, FIONREAD, &characters_buffered);
        tcsetattr(STDIN_FILENO, TCSANOW, &original);
    
        bool pressed = (characters_buffered != 0);
    
        return pressed;
    }
    
    // ********************************************************************
    
    
    inline unsigned long long fibolinear( long n ) {
      volatile static unsigned long long  fibarr[3]; 
      static long i;
    
      fibarr[0]=0;
      fibarr[1]=1;
      fibarr[2]=0;
    
      if(n==0) return 0;
    
      for (i=1; i <= n; i++) {
         
          fibarr[0]=fibarr[1];
          fibarr[1]=fibarr[2];
          fibarr[2]=fibarr[1]+fibarr[0];
          printf("\n order linear: %ld  %llu \n" , i, fibarr[2]);       
      }
      return fibarr[2];
     
    }
    
    
    
    inline unsigned long long fiborecurs( long n ) {
      unsigned long long   llbuf;  
      volatile static long order = 0;
    
      pthread_testcancel(); // <<<<<<<<<<<<<<<<<<<< oder mal weglassen!
    
      if ( n==0 )    { llbuf = 0;  }
      else   
      if ( n==1 )    { llbuf = 1;  }
      else {
        
         llbuf = fiborecurs(n-1) + fiborecurs(n-2);         
         if(n > order) {
             order = n;
             printf("\n order recursive: %ld  %llu \n" , order, llbuf); 
         }     
      }
      return (llbuf); 
    }
    
    
    
    // ********************************************************************
    
    
    
    
    void* threadf2(void *) {
        unsigned long long res;
        int RETVAL = 0;
           
        res = fibolinear(f);
        
        printf("\n\nFibonacci (%ld) (linear) is = %llu \n", f, res);     
        printf("===============================================\n\n"); 
    
        running2 = 0;
        msleep(100);
        
        return (void*)RETVAL; ;
        
    }
    
    
    
    void* threadf1(void *) {
        unsigned long long res;
        int RETVAL = 0;
     
        res = fiborecurs(f);
        
        printf("\n\nFibonacci (%ld) (recursive) is = %llu \n", f, res); 
        printf("===============================================\n\n");    
        
        running1 = 0;
        msleep(100);
        
        return (void*)RETVAL; ;
        
    }
    
    
    
    
    void* threadW0(void *) {
        int RETVAL = 0;
        
        while(running1 || running2) {
     
          if (kbhit())
          {
             int ch = getchar();
             if(ch==27) {       
                // DEBUG    
                printf("\nin pthread0: user kbd press ESC...  ");  
                printf("\npthread0 cancelling pthread 1... ");                         
                if(threadID1) pthread_cancel(threadID1);
                
                // DEBUG 
                printf("\npthread0 cancelling pthread 2...");             
                if(threadID2) pthread_cancel(threadID2);
                
                running1 = 0;
                running2 = 0; 
                
                // DEBUG 
                printf("\nin pthread0: program interrupted by user  \n");
                
                RETVAL = 27;  // user break  
                return (void*)RETVAL; 
             }   
          }   
          msleep(1000);
          printf(".");
          fflush(stdout);
        }
        return (void*)RETVAL; 
        
    }
    
    // ********************************************************************
    
    
    int main() {	   
        void *retval0 = NULL, *retval1 = NULL, *retval2 = NULL;
        
        printf("enter Fibonacci order: ");
        scanf("%ld", &f);      
        
        pthread_create( &threadID1, 0, threadf1, 0 ); 
        pthread_create( &threadID2, 0, threadf2, 0 ); 
        pthread_create( &threadID0, 0, threadW0, 0 ); 
        
             
        pthread_join( threadID0,  &retval0 );
        pthread_join( threadID1,  &retval1 );    
        pthread_join( threadID2,  &retval2 );
        
        // DEBUG
        printf("\nretval0 = %d \n", (int)retval0);
        printf("\nretval1 = %d \n", (int)retval1);
        printf("\nretval2 = %d \n", (int)retval2);
        printf("\nprogram finished \n");
    
        return 0;
        
    }
    Geändert von HaWe (25.10.2016 um 23:25 Uhr)

  6. #6
    Benutzer Stammmitglied
    Registriert seit
    19.05.2015
    Beiträge
    69
    Das liegt aber nicht an pthread_testcancel() sondern an deinem msleep()-Makro, welches den Test auf einen Tastendruck nur einmal in einer Sekunde ausführen läßt.
    Reduzier das doch mal auf 1ms - mal sehen was dann raus kommt.

    Gruss botty
    Geändert von botty (26.10.2016 um 01:28 Uhr)

Ähnliche Themen

  1. .:Anfänger Frage zu Sensoren:.(Neu! Frage zu meinem 1. Progr
    Von oceans94 im Forum Sensoren / Sensorik
    Antworten: 22
    Letzter Beitrag: 06.05.2008, 06:54

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen