![]() |
Thread sichere Datenabfrage
Guten Morgen,
(Falls dieses Thema zweimal auftaucht tut es mir leid, mein erster Versuch Wollte nicht so richtig, kann aber sein das er doch noch durchrutscht):? Ich arbeite jetzt seit zwei Jahren mit Delphi (derzeit 10.4.1) und bin nun das erstemal an einem Punkt an dem ich nicht recht weiter komme und auch Online finde ich grade entweder nicht die richtigen Schlagworte oder habe einfach Verständniss Probleme...:oops: Das Drumherum: Ich habe einen Mainthread der Daten von einem Gerät ausliest und diese sowohl auf dem Monitor darstellt als auch immer hinten an eine Datei anhängt. (eigentlich sind das mehrere threads aber das tut soweit) Nun habe ich einen zweiten Thread gebastelt, der diese Daten einließt (wirklich nur liest) und auswertet. Dann schreibt er die Ergebnisse in eine andere Datei. Wenn ich in der Messung zurückScrolle sollten dann diese Ereignisse auch vom Main thread ausgelesen und dargestellt werden können. Da die Ergebnisse Variieren lese und werte ich immer alles ein/aus. Das könnte man ändern wäre aber sehr aufwendig und ich bin mir nicht sicher ab das am generellen Problem etwas ändert. Mein basis Problem: Manchmal kommt es bei mir zu einer Art Integerüberlauf - ich habe bisher noch nie Zugriffsverletzungen oder derlgeichen bekommen und bin mir nicht sicher woran es liegt.
Delphi-Quellcode:
1. Ich bin mir immernoch nicht ganz sicher ob einfaches Lesen beim Multithreading ein Problem darstellt?? Ob dabei Müll rauskommt wäre mir an der Stelle auch egal, das Fange ich Ohnehin ab. Aber stellt das Prinzipiell ein Problem dar? DieKlasse = class private FDataReader : TMyBufferedFileReader; FReadDataValueNum: Int64; //... und andere end; Function DieKlasse.ReadInData(var Abuf: TMyData):Cardinal; var idx: Int64; begin if FReadDataValueNum >= FDataReader.ValueCount then begin idx := FReadDataValueNum - FDataReader.ValueCount; if idx < length(FOnlineWriteCache) then begin ABuf := FOnlineWriteCache[idx]; //Hier entsteht der fehler(sehr sporadisch) wenn idx zu groß wird (was ja aber eigentlich gar nicht sein kann) result := 1; end else begin result := 0; end; end else begin FDataReader.ValueNumber := FReadDataValueNum; result := FDataReader.Read(ABuf, 1); end; end; 2. Muss ich die Abfragen der Streams in critical Sections packen oder gibt es hier befehle (vorgefertigt) die das Lesen und schreiben bereits Threadsicher machen? Alla: "ReadThisFileAndLockItWhileDoingSo" 3. Wenn ich Critical sections einführe sperren diese dann auch alle Variablen/Dateien usw. die ich innerhalb dieser Section verwende? Über ein wenig Rat wäre ich super dankbar. Das Thema Threads ist mir einfach immernoch nicht 100% geheuer. Lieben Gruß Kishmet PS: Vielen dank für das Tolle Forum und die Tollen Beiträge vom harten Kern! Ihr seit echt Spitze und ich hab schon soooo viel von euch gelernt!:thumb: |
AW: Thread sichere Datenabfrage
hm... also hier mal meine Gedanken zu dem Thema:
wenn FReadDataValueNum >= FkanalDatareader.ValueCount ist, dann kann folglich in der nächsten Zeile idx nicht negativ oder zu groß werden. Außer ein anderer Thread ändert just in dem Moment den ValueCount.... Korrekt? Ist die Einzige logische Erklärung die mir noch einfällt.... Wobei er eigentlich auch nicht zu groß werden kann da ich das ja wiederum abfrage und dann eh raus bin... Noch dazu tritt das nur sporadisch auf, daher ist es so schwer für mich zu kontrollieren was tatsächlich drin steht... |
AW: Thread sichere Datenabfrage
Überall muß um alles, was auf diese Variablen zugreift, die selbe CriticalSection (oder Ähnliches, z.B. siehe
![]() Nur Lesend, wenn währenddessen nirgendwo Schreibend zugegriffen werden kann, da kann man es auch ohne Synchronisation machen, aber nur wenn beim Lesezugriff nichts geschrieben wird. z.B. Stream.Read ist ein schreibender Zugriff, da dort der Posiotionszeiger verändert wird. Auch Lesend auf eine String-Variable oder Interface-Zeiger zugreifen ist ein schreibender Zugriff, aber die Referenzzählung ist mit den nachfolgend erwähnten atomaren Operationen gelöst. Zuweisen/Ändern von Integern/Pointer, da gibt es auch die Möglichkeit von "atomaren" Zugriffen durch die CPU, siehe ![]() Mehrfach auf den "selben" Wert zugreifen, dann vorher in eine lokale Variable kopieren. z.B.
Delphi-Quellcode:
if myvar > 0 then MachwasMit(myvar);
nur Windows: ![]() ansonsten siehe ![]() ![]() oder LOCK im Assembler. ![]() ![]() |
AW: Thread sichere Datenabfrage
Herzlich willkommen.
Konkret helfen kann ich nicht, aber falls Du die Kanäle nicht kennst, dann schau Dich mal dort noch um: ![]() ![]() PS: Trage mal noch Deine Delphi-Version in Deinem Profil ein. |
AW: Thread sichere Datenabfrage
Zitat:
Zitat:
Zitat:
Jetzt nochmal eine Frage von Oben, die ist noch nicht so richtig beantwortet worden glaube ich: Gibt es eine Lese bzw. eine Schreibfunktion in der von Haus aus eine Lock integriert ist? und erst wenn das Fertig ist, kann ein anderer thread wieder darauf zugreifen? |
AW: Thread sichere Datenabfrage
Hallo.
Ein mMn sehr guter Beitrag zum Thema Synchronisation von Bernd Ua: Video: ![]() Material: ![]() Zitat:
Beispiel dazu hier: ![]() Evtl ist auch TMultiReadExclusiveWriteSynchronizer für dich der richtige Weg. Auszug aus dem o.g. PDF: TMultiReadExclusiveWriteSynchronizer : • Verwaltet mehrere lesende Zugriffe und blockierenden Schreibzugriff • BeginRead/EndRead zum Lesen • BeginWrite/EndWrite zum Schreiben • Zum Beispiel verwendet von der VCL via IReadWriteSync in Forms (GlobalNamespace) In dem Buch "Delphi Cookbook" gibt es, glaube ich, ein Beispiel für ein Oszilloskop was auf Multi-Threading basiert. Die Problemstellung klang jetzt auf Anhieb irgendwie ähnlich. Tut mir leid, dass ich keine konkretere Hilfe anbieten kann. |
AW: Thread sichere Datenabfrage
hihi :-D das video hab ich grade auf. Danke dir @Reaktor
Mein größtes Problem ist grade tatsächlich auch das generelle Verständniss, was aber vermutlich einfach daran liegt das der Code in dem ich arbeite schon die eine oder andere zeile hat... und davon auch einfach viel nicht von mir ist, sondern von jemandem den ich deswegen auch nicht mehr fragen kann... :? Zitat:
Prinzipiell sollte es auch bei mir irgendwo in der Nähe des Codes zum schreiben und lesen bereits etwas geben was die threadsicherheit garantiert. Denn es geht ja auch das Rückblättern schon, wäre das nicht sicher dürfte auch dieser Teil nicht richtig funzen, ich bin leider bisher nicht dahinter gekommen, wie das genau funktioniert: Da keine critical section, Monitor synchronize oder sonstiges aufgerufen wird, ist das für mich grade nicht ganz plausibel... Das einzige was mir auffällt ist das die Lese und Schreib Prozesse über Pointer verbogen werden o.O . Vielleicht liegt es aber auch daran das die Datei jeweils zwischen gebuffered wird. So richtig Sinn bekomme ich in die Sache nur leider heute iwie nicht rein... Zitat:
|
AW: Thread sichere Datenabfrage
Statt CriticalSection gibt es seit 'ner Weile auch TMonitor.
(Achtung, nicht das TMonitor aus TScreens sondern aus System ... ja, ich weiß der Name ist doof/irrsinnig/verwirrend, aber wenn jemand strunzdoof von C# klaut kopiert, dann kommt sowas bei raus) Die TMonitor können an ALLE TObjekt angehängt werden. Besonders geil, weil man so keine Extra-Variable braucht und es sogar ohne Umbauten an Fremdkomponenten nutzen kann (z.B. an einer TStringList).
Delphi-Quellcode:
Statt TMonitor.Enter geht auch MonitorEnter
TMonitor.Enter(MyList); // siehe auch TryEnter/Wait/Pulse und der Timeout im Parameter
try finally TMonitor.Exit(MyList); end; und könnte man sich auch selbst via ClassHelper als Methoden an TObject/TMyList/... hängen.
Delphi-Quellcode:
MyList.Enter; // oder z.B. Lock und Unlock
try finally MyList.Exit; end; |
AW: Thread sichere Datenabfrage
Ist dein Programm reinzufällig 32 bit?
Wenn ja und der von dir angegebene Code einigermaßen der Realität entspricht und die Threads so laufen, wie ich es denke, hätte ich eine mögliche Erklärung. zu finden unter: ![]() Dort werden ein paar (nicht gleich so eindeutige) Fallstricke bei geteilten Ressourcen erklärt. Ein Beispiel geht um die Problematik mit 64 bit Datentypen (int64) wenn der Processor im 32 bit Modus arbeitet. Um die Variable auszulesen braucht der Prozessor zwei Schritte. Und zwischen diesen beide Schritten kann der Writer-Thread den noch nicht gelesenen Teil überschreiben. Je nachdem was der Writer-Thread nun manipuliert, könnte es FReadDataValueNum oder FDataReader.ValueCount sein. Dadurch kommt für idx ein nicht plausibler Wert raus und dann scheitert auch der Zugriff das Array oder die Liste. Das könnte auch das sporadische Auftreten erklären. Selbst wenn das jetzt nicht die Ursache ist, fand ich den Beitrag irgendwie spannend. Das Buch kann ich auch empfehlen, falls man das hier überhaupt darf. Zitat:
Zitat:
Auf jeden Fall musst du dich um die Synchronisation kümmern. Such am besten erstmal ob das nicht schon irgendwo passiert. Soweit ich das verstanden habe, kannst du eine Critical section relativ weit "außen" setzen, also z.B. gleich bei der ersten Funktion, die dann weitere Funktionen aufruft (Ich finde leider die Quelle dazu nicht mehr. Bitte korrigiert mich, wenn das nicht stimmt). Gut möglich, dass dein ehemaliger Kollege die Synchronisation auf einer anderen Ebene eingebaut hat. Der, durch CS geschützte Code, sollte allerdings wegen Deadlocks und Performance so kurz wie möglich bleiben. Und es müssen natürlich alle Threads auf die CS eingehen, nicht nur einer. Ist keine Synchronisierung vorhanden, musst du diese (unbedingt!) einbauen. Aber an welchen Stellen und mit welchen Mitteln, kann ich leider von außen nicht beurteilen. Halt immer dort wo es vorkommen kann, dass zwei oder mehrere Threads auf eine geteilte Ressource zugreifen. Gut möglich, dass es an den Pointern oder den Dateien liegt. Evtl auch das Bit-Problem oder einfach nur ein ungeschützer Zugriff auf Variablen oder Klassen. Hier noch ein kleiner Link zu CS: ![]() und hier noch einer zu simplen Datentypen und deren Threadsicherheit: ![]() Viel Erfolg! |
AW: Thread sichere Datenabfrage
Zitat:
Das werde ich mir Montag mal in Ruhe ansehen. Das könnte durchaus so sein. Das würde mich allerdings dezent verunsichern, denn ich nehme Codeelemente die mehr oder minder genauso auch an anderen Stellen für ähnliche Zwecke verwendet werden ... Ich Tippe aber drauf das ich wirklich noch irgendeinen Mechanismus zum Sperren einfach immernoch nicht gefunden habe, der in irgendeiner Hintertür eingebaut ist. Die Reader und Writer Elemente sind einfach extrem verschachtelt. Die Basics und auch wie ich eine CS verbaue habe ich drauf. Ich denke das ich auch mit dem TMonitor gut zurecht kommen würde (bisher nie verwendet). Mit amphoren und so weiter habe ich gottseidank noch keine Berührungspunkte, das wird aber vermutlich in ein oder zwei Jahren dann unumgänglich :shock: . Mal sehen wie sich das Projekt weiterentwickelt. Über das Wochenende werde ich einfach mal einen Test mit vielen Daten starten. Wenn es mir bis Montag um die ohren fliegt weiß ich wenigstens sicher das es ein Problem gibt. Sonst muss ich weiter suchen bis ich die Lösung gefunden habe. Ich danke euch für den großartigen Input! Ich mach mich mal auf die Suche und melde mich sobald ich was herausfinde! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:49 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz