Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Gibt es eine Eventqueue für nicht beendete Events?
JoelH - Di 16.06.15 13:45
Titel: Gibt es eine Eventqueue für nicht beendete Events?
Folgendes Problem, ich habe eine Anwendung die viel mit Datenbankenzugriffen arbeitet und deren Anwender ab und an offenbar zu schnell sind. Dadurch kommt es vereinzelt zu Race Conditions und Daten werden fehlerhaft manipuliert. Durch massives Flag setzen bin ich dem Ganzen zwar gut zu Leibe gerückt und konnte das Ganze auf genau eine Function eingrenzen. Aber hier kommt es sporadisch immer mal wieder vor (alle paar Monate). Nun habe ich mir die Frage gestellt ob es eventuell eine Eventqueue gibt die ausstehende bzw. noch nicht beendete Event Application weit bereitstellt. Denn damit wäre es ja ein leichtest so lange zu warten bis keine potenziellen Aufrufe mehr im Raum stehen und erst dann fort zu fahren.
Xion - Di 16.06.15 21:12
Von so einer Queue weiß ich nichts, aber es muss natürlich irgendwo eine geben. Vermutlich aber innerhalb des Betriebssystems.
Du kannst dir aber deine eigene Queue schreiben. Alle messages kommen in der Methode WndProc an. Die kannst du überschreiben und dann die Messages filtern (z.B.). Ein Beispiel für WndProc findest du unter
http://www.entwickler-ecke.de/viewtopic.php?t=109237. Ungefähr so sähe das dann wohl aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TStoppuhr.WndProc(var msg : TMessage); begin Queue.Push( msg ); end;
procedure QueueProcess(); begin while not doBlockMessage(Queue.firstMessage) do inherited WndProc(msg); end;
function doBlockMessage(msg: TMessage): boolean; begin if msg.msg=WM_LBUTTONDOWNthen Result := not isButtonDownHandlerRunning else Result := true; end; |
jfheins - Mi 17.06.15 00:09
Solange man Application.ProcessMessages vermeidet, sollte das soch eh nicht vorkommen!?
Denn dann wird eine Nachricht ja vollständig abgearbeitet, bevor die nächste rein kommt. Es gibt ja für jeden Thread die Windows-eigene Messagequeue.
Wenn man natürlich Application.ProcessMessages einsetzt, muss man überall Flags setzen und wundert sich über Race Conditions innerhalb eines einzigen Threads ... :roll:
Mein Rat also: Alles was lange dauert anständig in einen Thread auslagern - beim Rest die GUI blockiert lassen :angel:
Notnagel: Eine Funktion, die lediglich Resize- und Paint-Nachrichten verarbeitet, statt Application.ProcessMessages einsetzen.
JoelH - Mi 17.06.15 07:30
jfheins hat folgendes geschrieben : |
Solange man Application.ProcessMessages vermeidet, sollte das soch eh nicht vorkommen!?
[..]
Notnagel: Eine Funktion, die lediglich Resize- und Paint-Nachrichten verarbeitet, statt Application.ProcessMessages einsetzen. |
Das ist das Problem dabei, da "unterwegs" immer mal wieder die Statusbar repaintet werden will, wie auch diverse andere Statusanzeigen gibts m.E. kaum eine einfachere Möglichkeit als Application.ProcessMessages. Des Weiteren kommen aber auch via UDP-Messages Nachrichten rein die ggf. Datanbankzugriffe aus- und wieder anschalten kann, bzw. ebenfalls wieder visuelle Informationen direkt an den User weitergibt. Im Prinzip ist es so, dass ich das ganze relativ gut eingrenzen kann auf wenige onExit-Events die offenbar zu der Verwirrung führen. Und da dachte ich eben, wenn ich die aus einer Queue ausfiltern kann, dann reicht das schon, anstatt noch eine Reihe von Flags einzuarbeiten.
@zion
Das werde ich mal ausprobieren.
jfheins - Mi 17.06.15 18:12
Also wenn es nur ums Repainten geht, dann wäre vll sowas interessant:
http://stackoverflow.com/a/2183938/1974021
Wenn du das aufrufst (statt Application.ProcessMessages) dann werden nur Paint-Nachrichten verarbeitet, also keine Button-Callbacks oder ähnliches. Natürlich auch keine Tastendrücke.
Wenn das immer noch nicht das ist, was du willst, dann muss ich nochmal nachhaken um dein Problem zu verstehen. Szenario:
1. User klickt Button A. Dieser erledigt viel Arbeit im GUI Thread.
2. User klickt Button B.
3. Callback aus Schritt 1 ruft Application.ProcessMessages auf, was zur Ausführung des Callbacks von Button B führt.
4. Button B soll jetzt "warten" bis das Callback von Button 1 abgeschlossen ist?
Wenn ja: No way. Geht nicht.
Du könntest dir eine eigene ProcessMessages-Funktion schreiben, die einen "Abbruch"-Rückgabewert hat. Aber dann kommst du ja auch nur aus der innersten Funktion raus ;-)
Alternativ kannst du auch eine "zweite Messagequeue" aufmachen, in der du diese Sachen einträgst. Deine eigene ProcessMessages-Funktion incrementiert vor dem Aufruf van Application.ProcessMessages eine globale Variable und fecrementiert danach. Wenn am Ende Wert = 0 ist, eine Message an das eigene Fenster posten. In dem Callback dann nochmal prüfen und ggf. den ersten Wert aus dieser zweiten Queue ausführen.
Zusammengefasst: Mach es halt gleich richtig. Lied: Kurzes Einfrieren kann man vll. in Kauf nehmen, lange Berechnungen in einen Thread auslagern.
JoelH - Do 18.06.15 10:12
jfheins hat folgendes geschrieben : |
Also wenn es nur ums Repainten geht, dann wäre vll sowas interessant: http://stackoverflow.com/a/2183938/1974021
Wenn du das aufrufst (statt Application.ProcessMessages) dann werden nur Paint-Nachrichten verarbeitet, also keine Button-Callbacks oder ähnliches. Natürlich auch keine Tastendrücke.
|
Das sieht vielversprechend aus, werde ich mal probieren.
jfheins hat folgendes geschrieben : |
Wenn das immer noch nicht das ist, was du willst, dann muss ich nochmal nachhaken um dein Problem zu verstehen. Szenario:
1. User klickt Button A. Dieser erledigt viel Arbeit im GUI Thread.
2. User klickt Button B.
3. Callback aus Schritt 1 ruft Application.ProcessMessages auf, was zur Ausführung des Callbacks von Button B führt.
4. Button B soll jetzt "warten" bis das Callback von Button 1 abgeschlossen ist?
Wenn ja: No way. Geht nicht.
|
So ungefähr. Grundsätzlich kann man sagen, das Programm stellt zum großen Teil Eingabemasken zur Verfügung die stets auf onExit (Focusverlust) reagieren und dann unmittelbar die Daten in die Datenbank schreiben. Da die Masken aber ebenso als Suchmasken dienen, muss natürlich sichergestellt sein, in welchem Modus man sich gerade befindet. Dazu kommen des Weiteren Neuanlagen sowie Fremdmanipulationen der Daten durch andere Mitarbeiter, die auch berücksichtigt werden müssen. Des Weiteren muss entsprechend bei Wechseln immer alles in der GUI refreshed werden, da Felder natürlich auch Abhängigkeiten haben und ggf. neu berechnet werden müssen. Unter Umständen hängen da diverse neuerliche Datenbank Zugriffe dahinter sowie informierende Netzwerkkommunikation der Clients untereinander. Und da der User darüber informiert sein soll gibt es natürlich die Statusbarupdates etc. Was alles via Application.ProcessMessages am laufen gehalten wird, aber m.E. auch die Inkonsistenz reinbringt. Der User kann mittels Shortcuts ziemlich schnell durch die verschiedenen Modi springen und dabei eine ungewollte Parallelbearbeitung auslösen, die dann unerwartete Daten schreibt. Zumindest erscheint mir das Szenario so zu sein, da sich das natürlich nicht wirklich debuggen lässt, da beim Debuggen das Programm genug Zeit hat alles zu erledigen, zumal parallel arbeitende User nur schwer in eine solche Session einzubeziehen sind.
Und deshalb meine Frage nach der Queue, denn das Betriebssystem muss ja irgendwo Buch führen was noch alles aussteht, bzw. woran noch gearbeitet wird. Wenn mein Programm diese Liste auslesen könnte, dann könnte es sehr leicht feststellen ob noch etwas aussteht bzw. in Arbeit ist, was einen regelgerechten Ablauf beeinflussen könnte.
jfheins hat folgendes geschrieben : |
Zusammengefasst: Mach es halt gleich richtig. Lied: Kurzes Einfrieren kann man vll. in Kauf nehmen, lange Berechnungen in einen Thread auslagern. |
Es kommt hochgerechnet bei 150.000 Datenmanipulationen einmal vor. Dafür das gesamte Projekt zu redesignen ist der Mühe nicht wert, da ist es einfacher die potenziell fehlerhaften Einträge in der Datenbank grob auszufiltern und bei Bedarf manuell einzuschreiten.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!