@nvertigo
in: cThread::StartThread
pthread_detach(Thread->childTid); // auto-reap
return NULL;
bei mir läuft vdr auch amok wenn ich mit aktivem valgrind tune.
das habe ich mir nicht so genau ansgeschaut.
@nvertigo
in: cThread::StartThread
pthread_detach(Thread->childTid); // auto-reap
return NULL;
bei mir läuft vdr auch amok wenn ich mit aktivem valgrind tune.
das habe ich mir nicht so genau ansgeschaut.
Wenn der Thread dann aber abstürzt, werden seine Ressourcen nicht abgeräumt. Deshalb wird das ja im Thread-Kontext des startenden Threads aufgerufen.
Bedeutet das also, dass valgrind mit detached threads nicht gut zurechtkommt?
@mini73
wenn im Thread ein malloc gemacht wird,
dann denkt valgrind das dieses malloc nicht mehr freigegeben wird, da ja bereits pthread_detach aufgerufen wurde.
zumindest ist das meine beobachtung.
'childTid' ist zu diesem Zeitpunkt u.U. noch nicht gesetzt, daher wird der Thread wohl keine Resourcen freigeben.
Ausserdem ist StartThread() 'static' und hat daher keinen Zugriff auf ein 'childTid'. Wenn, dann müsste es wohl 'Thread->childTid' heissen, aber das ist, wie gesagt, zu diesem Zeitpunkt womöglich noch nicht gesetzt.
Ich muss gestehen, dass mir der Unterschied zwischen 'childTid' und 'childThreadId' jetzt auch nicht so ganz klar ist.
Thread->childTid habe ich korrigiert.
damit childTid auch gültig ist sollte man nach einem erfolgreichem pthread_create() - auf den thread warten.
z.B mit Funktion WaitForThreadStart und Variable bThreadStarted (bThreadStarted muss natürlich im konstruktor mit false initialisert werden)
void *cThread::StartThread(cThread *Thread){
Thread->bThreadStarted = true;
..
}
Bsp für WaitForThreadStart:
void cThread::WaitForThreadStart()
{
struct timespec req, rem;
req.tv_sec = 0;
req.tv_nsec = 1000;
cTimeMs timeout;
timeout.Set(0);
while (!bThreadStarted){
uint64_t elapsed = timeout.Elapsed();
if (elapsed > 500) //nach 500ms aufgeben{
esyslog("ERROR: WaitForThreadStart Timeout 500ms %s", description ? description : "");
break;
}
else{
nanosleep(&req , &rem);
}
};
}
Display More
So, wie ich die Diskussion zu valgrind und pthread im Internet verstehe, werden die Ressourcen der noch laufenden detached pthreads bei Programmende erst später freigegeben, als valgrind das wohl mag.
Aber all zu tief bin ich da auch nicht drin.
@mini73
ich habe folgendes beobachtet:
valgrind bemerkt dass ein thread gestartet wird, und regsitriert malloc/new aus diesem thread.
Wenn nun vor thread ende ein pthread_detach gemacht wird, denkt vargrind das der thread speichlecks hat.
Wenn pthread_detach gemacht wird, bevor im thread ein malloc/new gemacht wird (zufall), dann meckert valgrind nicht.
speicher-leck suche ist dadurch schwierig.
Klingt nach einem Problem in valgrind...
keine ahnung ob man hier von einem problem sprechen kann.
eventuell sollte man über Solution 3 nachdenken:
https://stackify.dev/907998-valgrin…-pthread-create
meine lösung ähnelt Solution 2.
Solution 3 klingt eher wie eine Anleitung für Solution 1.
Aber ja, gleich das detach beim create mitgeben, klingt nach einer guten Idee.
Und da, wo jetzt das pthread_detach steht, könnte man dann das pthread_attr_destroy machen.
Hilft das hier?
diff --git a/thread.c b/thread.c
index 2d3580b..0a5e468 100644
--- a/thread.c
+++ b/thread.c
@@ -312,13 +312,17 @@ bool cThread::Start(void)
cCondWait::SleepMs(THREAD_STOP_SLEEP);
}
if (!active) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
active = running = true;
- if (pthread_create(&childTid, NULL, (void *(*) (void *))&StartThread, (void *)this) == 0) {
- pthread_detach(childTid); // auto-reap
+ if (pthread_create(&childTid, &attr, (void *(*) (void *))&StartThread, (void *)this) == 0) {
+ pthread_attr_destroy(&attr);
}
else {
LOG_ERROR;
active = running = false;
+ pthread_attr_destroy(&attr);
return false;
}
}
Display More
Würdest du diese .gitignore Datei in dein Repository aufnehmen? Das würde sehr helfen. Natürlich ohne das .txt
Ich wollt Erfolg melden! Zur Veranschaulichung hier einmal der Speicherverbrauch des VDR in tabellarischer Ausführung:
DATE TIME TZ YEAR PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
Fr 24. Dez 00:06:03 CET 2021 1546 vdr 20 0 2436296 117464 14400 S 35,3 1,5 157:22.41 vdr
Sa 25. Dez 00:05:13 CET 2021 1546 vdr 20 0 2454704 139572 14424 S 23,5 1,8 493:51.31 vdr
So 26. Dez 00:08:05 CET 2021 1546 vdr 20 0 2454704 139908 14424 S 17,6 1,8 808:08.03 vdr
Mo 27. Dez 00:10:06 CET 2021 1546 vdr 20 0 2430116 142192 14056 S 23,5 1,9 1131:03 vdr
Di 28. Dez 00:06:16 CET 2021 1546 vdr 20 0 2454704 143088 14112 S 17,6 1,9 1448:05 vdr
Mi 29. Dez 00:08:34 CET 2021 1546 vdr 20 0 2460884 123444 14144 S 33,3 1,6 1781:01 vdr
Do 30. Dez 00:06:08 CET 2021 1546 vdr 20 0 2432188 144804 14144 S 33,3 1,9 2104:53 vdr
Fr 31. Dez 00:06:59 CET 2021 1546 vdr 20 0 2412264 166964 14996 S 27,8 2,2 2432:56 vdr
Sa 1. Jan 00:05:10 CET 2022 1546 vdr 20 0 2434812 187348 15016 R 16,7 2,5 2755:52 vdr
So 2. Jan 00:09:51 CET 2022 1546 vdr 20 0 2459400 225328 15104 S 35,3 2,9 3085:08 vdr
Mo 3. Jan 00:08:00 CET 2022 1546 vdr 20 0 2474824 229820 15104 S 22,2 3,0 3416:29 vdr
Di 4. Jan 00:07:25 CET 2022 1546 vdr 20 0 2439308 247632 14440 S 23,5 3,2 3766:32 vdr
Mi 5. Jan 00:05:43 CET 2022 1546 vdr 20 0 2441380 247576 14360 S 11,1 3,2 4097:56 vdr
Do 6. Jan 00:06:03 CET 2022 1546 vdr 20 0 2439308 249136 14340 S 23,5 3,3 4431:28 vdr
Fr 7. Jan 00:08:14 CET 2022 1546 vdr 20 0 2413708 221992 12680 S 22,2 2,9 4767:01 vdr
============================================== VDR Neustart ===========================================
Sa 8. Jan 00:08:14 CET 2022 12170 vdr 20 0 2278516 48620 6548 S 22,2 0,6 39:11.42 vdr
So 9. Jan 00:05:34 CET 2022 12170 vdr 20 0 2466960 121204 7672 S 22,2 1,6 344:13.51 vdr
Mo 10. Jan 00:08:27 CET 2022 12170 vdr 20 0 2422952 149924 7608 S 17,6 2,0 672:14.34 vdr
Di 11. Jan 00:05:48 CET 2022 12170 vdr 20 0 2425024 149464 5540 S 22,2 2,0 995:34.70 vdr
Mi 12. Jan 00:07:08 CET 2022 12170 vdr 20 0 2462900 169220 5488 S 35,3 2,2 1325:15 vdr
Do 13. Jan 00:05:41 CET 2022 12170 vdr 20 0 2438312 199048 5912 S 16,7 2,6 1675:35 vdr
Fr 14. Jan 00:06:34 CET 2022 12170 vdr 20 0 2438312 212932 6144 S 16,7 2,8 2004:32 vdr
Sa 15. Jan 00:06:10 CET 2022 12170 vdr 20 0 2438312 231268 7412 S 29,4 3,0 2344:03 vdr
So 16. Jan 00:08:35 CET 2022 12170 vdr 20 0 2440384 240916 7432 S 27,8 3,2 2674:03 vdr
Mo 17. Jan 00:09:02 CET 2022 12170 vdr 20 0 2438312 240856 7412 S 11,1 3,2 3000:23 vdr
Di 18. Jan 00:06:15 CET 2022 12170 vdr 20 0 2438312 241068 7452 S 17,6 3,2 3329:52 vdr
Display More
Und hier noch der Speicherverbrauch des gesamten Systems grafisch:
Man kann sehr schön sehen, dass der Sägezahn deutlich flacher geworden ist. Aber auch, dass der Speicherverbrauch vom VDR immernoch minimal wächst. In wie weit das normal ist, oder ob das noch andere Speicherlecks sind, weiß ich nicht. Ich werde das weiter beobachten, sowohl den Speicherverbrauch als auch diesen Thread hier.
Grüße
Marcus
pthread_attr_destroy kann man direkt nach thread create machen.
if (attrp) pthread_attr_destroy(attrp);
Solution 3 - signalisert valgrind das der thread detached läuft.
ansonsten weiß das valgrind ja nicht sofort (valgrind meckert wenn zwischen pthread_create und pthread_detach ein malloc/new gemacht wird).
ich habe das ganze so verstanden:
pthread_detach bewirkt das nach thread ende, alle thread ressourcen freigegeben werden.
vereinfachtes Beispiel:
pthread_create = erstellt ein globales handle mit nummer 1 (unser childTid).
wenn der thread beendet wird exisitert dieses handle weiter, damit childTid vom aufrufenden thread weiter gültig bleibt.
pthread_detach (egal woher es aufgerufen wird) bewirkt:
alle thread ressourcen (childTid) bitte nach thread ende freigeben.
die variable childTid ist ab diesem zeitpunkt unsicher.
es könnte sogar passieren das inzwischen ein anderes pthread_create die selbe id vergeben hat.
im vdr code wird das durch die variable Thread->threadrunning = false geprüft.
hier könnte man zusätzlich ein Thread->childTid=0 machen (falls man pthread_detach in den thread verschiebt - Solution 2).
Ich hab das pthread_attr_destroy zwei mal drin, weil es im Fehlerfall einen early-return gibt. Wenn das nur im if-Zweig aufgerufen würde, wäre es eine Lücke.
Wobei ich nicht weiß, ob das überhaupt nötig ist.
Wenn man bei pthread_create keine Attribute angibt, muss man entweder pthread_detach oder pthread_join aufrufen. Das kann man ja durch das Attribut wunderbar umgehen (wobei man dann pthread_attr_destroy stattdessen aufrufen muss - muss man oder sollte man? Die Manpage finde ich da nicht so ganz eindeutig).
Ich würde die Lösung mit den Attributen bevorzugen - es ist eindeutiger.
Und man ist nicht auf irgend einen Aufruf irgendwo an anderer Stelle angewiesen, der dann vielleicht auch nicht ausgeführt wird, falls im Thread eine Exception auftritt.
Würdest du diese .gitignore Datei in dein Repository aufnehmen?
Ich glaube, das Thema hatten wir schon mal (ich finde aber leider das Posting nicht mehr - vielleicht war es auch auf der VDR-ML).
Erstens mag ich keine Dot-Files verwalten, und zweitens hat da dann sicher jeder einen Vorschlag, was da noch alles rein soll ;-).
ich habe alle varianten durchgetestet - damit es schnell geht - mit einem TestThread.
verlässlich ist keine der varianten - alles ziemlich sinnlos.
am verlässlichsten funktioniert valgrind, wenn man in cThread::StartThread vor dem Aufruf von Action, ein sleep mit 200ms macht.
dann meckert valgrind nicht mehr.
"verlässlich" und "sleep" in einem Satz... 😂
Dann muss man solche Fehlmeldungen wohl einfach ignorieren. 200ms sind schon eine Menge Zeit und verändern ggf. auch das Verhalten des vdr, falls man das nur für Speicherlecks mal einbaut. Das scheint mir also auch keine Lösung zu sein.
für alle jene die eine specherleck suchen, und die valgrind ausgabe etwas verringern wollen, die müssen den vdr mit so einem sleep bauen.
aber auch 200ms ist nicht verlässlich, leider ist das ganze stark cpu (anzahl und auslastung) abhängig.
echt frustrierend.
zumindest liefert valgrind (auch ohne patches) nach dem beenden das richtige ergebnis.
die ausgabe zur laufzeit ist falsch.
LEAK SUMMARY:
==29891== definitely lost: 0 bytes in 0 blocks
==29891== indirectly lost: 0 bytes in 0 blocks
==29891== possibly lost: 0 bytes in 0 blocks
Das ist jetzt schon der zweite schwerwiegende Fehler im epg-search Plugin. Nur deswegen hatte ich meinen Ubuntu LTS Server geupdated und mir damit eine Tonne weiterer Probleme eingehandelt. Sehr sehr ärgerlich. Ich entwickle selbst seit 30 Jahren professionell Software in C++ und habe für solche Bugs kein Verständnis. Wenn man nicht weiß, was man tut - und es dann auch nicht testet - lässt man es besser.
Frage: Kommt der Bugfix in die offiziellen Repositories?
Don’t have an account yet? Register yourself now and be a part of our community!