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.
Fehlende Synchronisation, kann man z.B. per mutex machen oder durch entsprechende Datencontainer die Zugriffe aus mehreren Threads lockfrei umsetzen.
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.
Ja, die Speicherallokation fehlt komplett.
1 | int *tab; |
2 | |
3 | while(i < nbVal){ |
4 | printf("value %d: ", i); |
5 | scanf("%d", &val); |
6 | tab[i] = val; |
7 | i++; |
8 | }
|
@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.
:
Bearbeitet durch User
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).
:
Bearbeitet durch User
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.
In der Funktion entryValues():
1 | pthread_exit(tab); |
2 | 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():
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.
Rolf M. schrieb: > Das ist ein Speicherleck. Das findest du übrigens, wenn du mit -fsanitize=address baust und dann den Output anschaust:
1 | ================================================================= |
2 | ==36679==ERROR: LeakSanitizer: detected memory leaks |
3 | |
4 | Direct leak of 8 byte(s) in 1 object(s) allocated from: |
5 | #0 0x5599a23a45b9 in malloc (/tmp/test+0xc25b9) |
6 | #1 0x5599a23d9d53 in main /tmp/thread_neu.c:58:22 |
7 | #2 0x7fbec4340001 in __libc_start_main (/usr/lib/libc.so.6+0x27001) |
8 | |
9 | SUMMARY: AddressSanitizer: 8 byte(s) leaked in 1 allocation(s). |
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.
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 :/
:
Bearbeitet durch User
pthreads gibt es beileibe nicht nur unter Linux bzw. UNIX-artigen Betriebssystemen: https://en.m.wikipedia.org/wiki/POSIX_Threads
:
Bearbeitet durch User
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.