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.
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.
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.
@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.
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.
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.
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).
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.
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.
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():
1
int*arr=(int*)malloc(nbValues*sizeof(int));
2
pthread_join(tid1,(void**)&arr);
3
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.
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.
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 :/
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.