Forum: PC-Programmierung Pthreads: Pointer ausgeben und wieder als Parameter übergeben


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Yann B. (yann)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

Ich habe ein Programm mit 2 erstellten Threads mit den ids: tid1 und
tid2 und ich verwende den Thread mit tid1, um die Werte einzugeben, die
ich in den zweiten Thread mit tid2 miteinander summieren möchte, aber
das Ergebnis der Summe ist nicht korrekt. Ich habe dann versucht, in
tid2 die Werte anzuzeigen, die ich in tid1 eingebe und festgestellt,
dass auch diese nicht korrekt sind (nicht mit den eingegebenen Werten
übereinstimmen). Weißt einer/eine hier vielleicht, was ich falsch mache?
Die von tid1 zurückgegebenen Werte sind bereits korrekt.

Vielen Dank im voraus


Das Programm (thread.c) und eine Test-Ausgabe liegen als Anhang.

von xk (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Fehlende Synchronisation, kann man z.B. per mutex machen oder durch 
entsprechende Datencontainer die Zugriffe aus mehreren Threads lockfrei 
umsetzen.

von Εrnst B. (ernst)


Bewertung
0 lesenswert
nicht lesenswert
Yann B. schrieb:
> Das Programm (thread.c) und eine Test-Ausgabe liegen als Anhang.

Ersetz erstmal die threads durch normale Funktionsaufrufe, kompiliere 
mit allen Warnings enabled, und bring die Speicherverwaltung in Ordnung 
(valgrind o.Ä.).

Wenn das geht, dann kannst du die Funktionen wieder zu threads machen. 
Vorher machst du dir das Debuggen nur unnötig schwer.

von Εrnst B. (ernst)


Bewertung
0 lesenswert
nicht lesenswert
xk schrieb:
> Fehlende Synchronisation

ist es nicht, er startet ja einen thread, wartet bis der beendet ist, 
und startet dann erst den zweiten.

"fehlende mallocs" sind eher das Problem.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Ja, die Speicherallokation fehlt komplett.
   int *tab;

   while(i < nbVal){
      printf("value %d: ", i);
      scanf("%d", &val);
      tab[i] = val;
      i++;
   }

@Yann: Was denkst du denn, wo dein tab[i] = val seine Daten hinschreibt? 
tab selbst ist nur ein Zeiger, der erst einmal "in die Pama" zeigt, also 
irgendwo hin. Und den nutzt du munter, um dort deine Daten 
hinzuschreiben.

von Yann B. (yann)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
xk schrieb:
> Fehlende Synchronisation

Dke xk für dein Feedback, aber wie Ernst auch schon gesagt, glaubte ich 
nicht, dass das Problem an dieser Stelle daran lag.

Εrnst B. schrieb:
> kompiliere
> mit allen Warnings enabled, und bring die Speicherverwaltung in Ordnung
> (valgrind o.Ä.).
Danke Ernst für den Tipp! Das Enable der Warnings beim Kompilieren hat 
mir sehr geholfen und die Speicherverwaltung habe ich noch bearbeitet.

Εrnst B. schrieb:
> "fehlende mallocs" sind eher das Problem.

Richtig, das war genau das Hauptproblem.

Rolf M. schrieb:
> Ja, die Speicherallokation fehlt komplett.

Danke für die Bestätigung.
----------------------------------------------
Ich habe also den Code bearbeitet und es läuft jetzt wie ich mir 
vorgestellt habe, obwohl ich noch offene Fragen wegen einiger Warnungen 
habe. Aber diese werde später hier posten. Anbei liegt der bearbeitete 
Code.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Yann B. schrieb:
> Ich habe also den Code bearbeitet und es läuft jetzt wie ich mir
> vorgestellt habe, obwohl ich noch offene Fragen wegen einiger Warnungen
> habe. Aber diese werde später hier posten. Anbei liegt der bearbeitete
> Code.

Da liegt allerdings immer noch einiges im Argen bei der 
Speicherallokation.

von Sven B. (scummos)


Bewertung
0 lesenswert
nicht lesenswert
Kompiliere erstmal mit -fsanitize=address und behebe alle Fehler, dann 
sehen wir mal weiter. Tipp: kompiliere einfach immer mit 
-fsanitize=address, es gibt wenig Gründe das nicht zu tun außer man ist 
am profilen oder baut eine finale Version.

Und lass die Finger von Threads, damit schießt du dir nur in den Fuß. 
Arbeite dich mal ohne ein und wenn du einigermaßen sicher bist mit den 
Grundlagen kannst du dir anschauen, wie man typische Probleme mit 
Threads nach heutigem Stand der Technik am besten löst (Spoiler: so 
nicht).

: Bearbeitet durch User
von Yann B. (yann)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Da liegt allerdings immer noch einiges im Argen bei der
> Speicherallokation.

Hast du recht aber kannst du mir bitte genau sagen, was ich falsch 
gemacht habe. Sonst habe ich gestern beim Testen festgestellt, dass der 
Thread sumValues immer nur 2 Werte einliest und miteinander summiert, 
wenn ich aber als Anz der Values den Wert 3 z.B eingebe.

von Yann B. (yann)


Bewertung
0 lesenswert
nicht lesenswert
Sven B. schrieb:
> Kompiliere erstmal mit -fsanitize=address und behebe alle Fehler

Es gibt aktuell keine Fehler in der neuen geladenen Version, die nach 
dem Kompilieren angezeigt werden sondern nur einige Warnungen. Die 
meisten von diesen habe ich aber schon behoben.

von Yann B. (yann)


Bewertung
0 lesenswert
nicht lesenswert
Sven B. schrieb:
> Tipp: kompiliere einfach immer mit
> -fsanitize=address

Dke für den Tipp!

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
In der Funktion entryValues():
   pthread_exit(tab);
   free(tab);
Das free() ist toter Code, denn es kommt nie zur Ausführung, weil 
pthread_exit() den Thread vorher beendet. Das ist in diesem Fall aber 
auch gut so, denn tab dürfte dort auch nicht deallokiert werden.

In main():
   int *arr = (int*) malloc(nbValues * sizeof(int));
   pthread_join(tid1, (void**)&arr);
   printf("array: %d\n", arr[0]);

Zuerst allokierst du mit malloc nochmal einen weiteren Speicherblock und 
speicherst dessen Adresse im Zeiger arr. Direkt in der nächsten Zeile 
überschreibst du diesen Zeiger wieder durch die Adresse des in 
entryValues() allokierten Arrays. Damit ist die Adresse des zweiten 
Arrays für immer verloren und kann nicht mehr freigegeben werden. Das 
ist ein Speicherleck.

In sumValues allokierst du ein dritte Arrays und kopierst per memcpy 
alle Daten aus dem ursprünglichen Array dorthin. Das gibst du dann am 
Ende wieder frei. Das ist zwar an sich kein Fehler, aber komplett 
unnötig.

von Sven B. (scummos)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Das ist ein Speicherleck.

Das findest du übrigens, wenn du mit -fsanitize=address baust und dann 
den Output anschaust:
=================================================================
==36679==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 8 byte(s) in 1 object(s) allocated from:
    #0 0x5599a23a45b9 in malloc (/tmp/test+0xc25b9)
    #1 0x5599a23d9d53 in main /tmp/thread_neu.c:58:22
    #2 0x7fbec4340001 in __libc_start_main (/usr/lib/libc.so.6+0x27001)

SUMMARY: AddressSanitizer: 8 byte(s) leaked in 1 allocation(s).

von Mark B. (markbrandis)


Bewertung
0 lesenswert
nicht lesenswert
Sven B. schrieb:
> Das findest du übrigens, wenn du mit -fsanitize=address baust

Ist ja nicht gesagt, dass er den Code mit dem GCC kompiliert.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Mark B. schrieb:
> Sven B. schrieb:
>> Das findest du übrigens, wenn du mit -fsanitize=address baust
>
> Ist ja nicht gesagt, dass er den Code mit dem GCC kompiliert.

Aber doch recht wahrscheinlich. Alternativ kann man das Programm auch in 
valgrind laufen lassen.

von Sven B. (scummos)


Bewertung
-1 lesenswert
nicht lesenswert
Mark B. schrieb:
> Sven B. schrieb:
>> Das findest du übrigens, wenn du mit -fsanitize=address baust
>
> Ist ja nicht gesagt, dass er den Code mit dem GCC kompiliert.

Welche gebräuchlichen Compiler gibt es denn, mit denen man Programme die 
die pthreads-Header verwenden kompilieren kann, die aber nicht 
-fsanitize=address unterstützen? Quasi niemand verwendet unter Linux 
irgendwas außer den gcc und den clang, die das beide können. Wirkt es 
so, als ob der TO den Intel-Compiler benutzt? Für mich eher nicht.

Selbst wenn der TO macOS benutzen sollte (was nicht der Fall ist, der 
Screenshot im ersten Beitrag ist das Standard-Theme des 
Ubuntu-Terminalemulators), würde er dort mit fast völliger Sicherheit 
ebenfalls den clang benutzen.

Sprich, ein uc.net-typisch komplett sinnloser Quark-Beitrag, der 
irgendeinen Randfall in den Raum wirft, der völlig offensichtlich nicht 
realisiert ist -- sorry aber ist so :/

: Bearbeitet durch User
von Mark B. (markbrandis)


Bewertung
-2 lesenswert
nicht lesenswert
pthreads gibt es beileibe nicht nur unter Linux bzw. UNIX-artigen 
Betriebssystemen:

https://en.m.wikipedia.org/wiki/POSIX_Threads

: Bearbeitet durch User
von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Mark B. schrieb:
> pthreads gibt es beileibe nicht nur unter Linux bzw. UNIX-artigen
> Betriebssystemen:
>
> https://en.m.wikipedia.org/wiki/POSIX_Threads

Stimmt. Auf der Seite sind neben UNIX-artigen Systemen noch zwei Systeme 
genannt, nämlich DR-DOS und Windows, aber letzteres nur, wenn man 
entsprechende Erweiterungen dazu installiert hat. Jetzt können wir 
natürlich noch ewig darüber diskutieren, ob der TE sein 
Multitheading-Programm vielleicht unter DOS mit Watcom C laufen lässt 
oder so.
Also sagen wir es so: Für den sehr wahrscheinlichen Fall, dass er ein 
UNIX-artiges System mit einem halbwegs aktuellen gcc oder clang benutzt, 
kann er mal -fsanitize=address als Compiler-Option oder die Ausführung 
des Programms in valgrind probieren. Ansonsten muss er halt das 
entsprechende Pendant für sein System nehmen oder hier nochmal genau 
schreiben, was er stattdessen benutzt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.