Problem mit pthreads



  • Hallo!

    Ich soll für die FH ein Programm schreiben, welches unter Verwenndung von pthreads viele Zahlen aus 10 verschiedenen Dateien ausliest, den Mittelwert pro Datei, sowie den gesamten Mittelwert berechnet.

    Mein erster Versuch, der eigentlich nur bezwecken soll, dass ich überprüfen kann, ob die Daten überhaupt in den jeweiligen Threads ankommen, lautet so:

    #include <stdio.h>
    #include <pthread.h>
    #include <stdlib.h>
    
    struct ThreadData
    {
    char *dateiname;
    int threadnummer;
    };
    
    void Mittelwert_Berechnen(struct ThreadData*);
    
    int main()
    {
    struct ThreadData *td;
    int i;
    pthread_t threads[10];
    
    for(i=0;i<10;i++)
    {
    td=(struct ThreadData*)malloc(sizeof(struct ThreadData));
    (*td).dateiname=(char*)malloc(sizeof(char));
    
    (*td).threadnummer=i;
    sprintf((*td).dateiname,"zahlen%d.txt",i+1);
    
    threads[i]=pthread_create(&threads[i],NULL,(void*)&Mittelwert_Berechnen,td);
    
    //Mittelwert_Berechnen(td);
    }
    
    for(i=0;i<10;i++)
    {
      pthread_join(threads[i],NULL);
    }
    
    }
    
    void Mittelwert_Berechnen(struct ThreadData *td)
    {
    printf("Thread %d: %s\n",(*td).threadnummer,(*td).dateiname);
    pthread_exit(NULL);
    }
    

    und gibt mir folgende Meldung aus:

    /tmp/cckvo9fF.o: In function main': Aufgabe53.c:(.text+0x7b): undefined reference topthread_create'
    Aufgabe53.c:(.text+0xac): undefined reference to `pthread_join'
    collect2: error: ld returned 1 exit status

    und mir stellt sich jetzt natürlich die Frage nach dem warum.
    gibt es an dem Code sonst irgendetwas auszusetzen?
    in dem mir mitgegebenen Beispielcode werden in den Funktionen irgendwelche void-Zeiger verwendet. Kann ich das so machen, dass ich direkt Zeiger auf Datenstrukturen oder Datenstrukturen allgemein übergebe bzw. gilt auch hier die Regel, dass der Funktion eine Kopie der Parameter übergeben wird?



  • wie genau linkst du? (Es ist auf jeden Fall ein Linkerfehler)
    Ich glaube du brauchst ein -lpthread, aber bin jetzt auch zu faul um nachzuschauen.



  • OK danke! 😕



  • Nächstes Problem: Die Bildschirmausgabe bleibt aus.



  • OK habs soweit gelöst bekommen. Das Problem bestand darin, dass ich die Variablen in threads[] überschrieben habe. 😕

    so siehts dann jetzt aus, ich bekomme aber eine Warnung, dass die Funktion nicht als void* übergebe, also (void*)&funktion schreibe 🤡


  • Mod

    HansKlaus schrieb:

    Nächstes Problem: Die Bildschirmausgabe bleibt aus.

    Vielleicht solltest du erst einmal lernen, mit Dingen wie Zeichenketten umzugehen, bevor du dich an Threads wagst. Deine Behandlung von Zeichenketten ist hier vollkommen falsch. Du schreibst kreuz und quer im Speicher rum, kein Wunder, dass das nicht funktioniert.



  • Was meinst du da genau?

    Also der Code sieht jetzt so aus:

    #include <stdio.h>
    #include <pthread.h>
    #include <stdlib.h>
    
    struct ThreadData
    {
    char *dateiname;
    int threadnummer;
    };
    
    int summeges=0;
    int anzahlges=0;
    
    void* Mittelwert_Berechnen(struct ThreadData*);
    
    int main()
    {
    struct ThreadData *td;
    int i;
    pthread_t threads[10];
    
    for(i=0;i<10;i++)
    {
    td=(struct ThreadData*)malloc(sizeof(struct ThreadData));
    (*td).dateiname=(char*)malloc(25*sizeof(char));
    
    (*td).threadnummer=i;
    sprintf((*td).dateiname,"zahlen%d.txt",i+1);
    
    pthread_create(&threads[i],NULL,&Mittelwert_Berechnen,td);
    
    //Mittelwert_Berechnen(td);
    }
    
    for(i=0;i<10;i++)
    {
      pthread_join(threads[i],NULL);
    }
    
    printf("Summe aller Zahlen: %d Anzahl aller Zahlen: %d Mittelwert aller Zahlen: %d\n",summeges,anzahlges,summeges/anzahlges);
    
    return 0;
    
    }
    
    void* Mittelwert_Berechnen(struct ThreadData *td)
    {
    FILE *datei=fopen((*td).dateiname,"r");
    int summe;
    int anzahl;
    int zahl;
    
    if(!datei)
    {
      printf("Thread %d: Fehler beim Oeffnen der Datei %s.\n",(*td).threadnummer,(*td).dateiname);
    }
    else
    {
      summe=0;
      anzahl=0;
    
      for(;;)
      {
        if(feof(datei))
        {
          break;
        }
        else
        {
          fscanf(datei,"%d",&zahl);
          summe=summe+zahl;
          anzahl++;
        }
    
      }
    
      summeges=summeges+summe;
      anzahlges=anzahlges+anzahl;
    
    printf("Thread %d: Datei: %s Summe: %d Anzahl: %d Mittelwert: %d\n",(*td).threadnummer,(*td).dateiname,summe,anzahl,summe/anzahl);
    free((*td).dateiname);
    free(td);
    
    pthread_exit(NULL);
    }
    }
    

    gibt es da noch etwas dran zu verbessern?


  • Mod

    HansKlaus schrieb:

    Was meinst du da genau?

    Da du ja eine Korrektur des Fehlers vorgenommen hast, hast du das Problem und eine mögliche Abhilfe ja offenbar schon selber gefunden. Bloß mit dem Nachteil, dass dein Programm nun ein potentielles Speicherleck hat (bzw. davor hatte es das auch, aber nun funktioniert das Programm wenigstens). Es sollte stets derjenige eine Ressource freigeben, der sie auch angefordert hat. Dein malloc wird von main durchgeführt, dahin gehört auch das free.

    Bloß frage ich mich: Warum überhaupt malloc? Alles was du damit anforderst sind statische Speicherblöcke, warum dann nicht gleich alles als automatische Variable (also ganz normale Variablen), so das du dich um nichts mehr kümmern brauchst?

    gibt es da noch etwas dran zu verbessern?

    Ein paar komische Ausführungspfade, guck beispielsweise mal, was passiert, wenn eine Datei nicht gefunden wird (oder genauer: Was nicht passiert). Siehe oben zum Thema Speicherleck.

    Ich würde die korrekten Prototypen benutzen. Ein Thread erwartet eine Funktion mit void* als Argument, nicht einen Zeiger auf ThreadData. Das kann zwar kompatibel sein, muss es aber nicht.

    Du solltest mittels des Rückgabewerts melden, ob die Funktion überhaupt erfolgreich war. In der main rechnest du fröhlich weiter, selbst wenn die Dateien nicht gefunden wurden, was dann zu einer Division durch 0 führt.



  • In jedem Thread die globalen Variablen anzahlges , summeges zu aktualisieren ist eine race condition.
    thread_exit() ist kein Ersatz für return .


Anmelden zum Antworten