Überlappendes Application. ProcessMessages macht Unsinn
Ich habe folgenden Code:
mit WaitForRequest wird ein Wert (über TCP) angefordert, ReqUID ist ein Objekt. Eine Schreibroutine,welches die ReqUID füllt funktioniert ebenfalls. ReqUID ist ein Item aus einer Liste, wenn mehrere Anforderungen zur gleichen Zeit erfolgen. Der ermittelte Wert wird dann in das UID-Obkelt geschrieben, welches am längsten auf den Wert wartet. Klappt soweit alles bis auf folgendes Szenario: Ich habe 2 Requests (gleichzeitig), sprich, WaitForRequest(jeweils andere UID) wird 2x aufgerufen und damit auch das Application.ProcessMessages. jetzt schreib ich einen Wert in das erste UID und ändere UID.RequestStatus = rsRequested und damit soll das WHILE abgebrochen werden. Pustekuchen. erst wenn ich den 2. Wert geschrieben habe und damit alle (wartenden) UIDs auf rsRequestet gesetzt habe gehts weiter. Ich vermute, daß mit dem 2. Aufruf von WaitForRequest (und damit ProcessMessages) der erste auf Aussetzen ist und damit das WHILE nicht abgebrochen wird (siehe LOG unten)
Code:
// WERTEANFORDERUNG klappt
if WaitForRequest(ReqUID) then begin ....
Code:
// Wartet bis Wert da ist oder TimeOut - und hier steckt ein Fehler oder Seiteneffekt
function TCallbackValue.WaitForRequest(const UID:TCBUID):boolean; const OneMilliSecond = 1 / (24 * 60 * 60 * 1000); begin UID.RequestStatus := rsRequesting; // CODE fürs Wert anfordern spielt hier keine Rolle und funzt // Timeout setzen UID.TimeOutTime := Now + OneMilliSecond * RequestTimeout; // Warten while (Now<UID.TimeOutTime) and (UID.RequestStatus = rsRequesting) do begin LOG(UID.Index); // hier habe ich testhalber mal geloggt Application.ProcessMessages; end; result := UID.RequestStatus = rsRequested; end; das LOG der gesamte Geschichte (siehe ProcessMessages-Code): /request #1 (UID#1) 1 1 1 /request #2 (UID#2) 2 2 2 2 /schreibe UID#1 (und RequestStatus = rsRequested) -> hier soll der erste Aufruf des ProcessMessages enden, MACHT ES ABER NICHT 2 2 ... 2 2 /schreibe UID#2 (und RequestStatus = rsRequested) 2 1 /fertig, beide bekommen den wert, nur daß UID#1 erst auf UID#2 gewartet hat :( es ist wichtig, daß immer die älteste Anforderung den Wert bekommt. so, ich hoffe, ihr versteht, was ich meine, HEEELLPPPP !!!!! [edit=sakura] Leerzeichen in Titel gesetzt. Mfg, sakura[/edit] |
Re: Überlappendes Application.ProcessMessages macht Unsinn
Okay, ich beantworte mittlerweile mein Problem selbst :)
Das ganze führt zu einer Rekursion. Also 1. ProcessMessages läuft: Eine MSG (bspw. Timer) löst in derselben Application ein 2. ProcessMessages aus. Dann bekommt, solange das 2. ProcessMessages läuft, das 1. ProcessMessages keine Rückmeldung, ist ja noch nicht zurückgekehrt. Danke Proddi :) Problem nur: Wie löst man sowas auf eine andere Art, sodaß das Programmhandling ungefähr gleich bleibt ? |
Re: Überlappendes Application.ProcessMessages macht Unsinn
Also, ich denke nicht, dass es am
Delphi-Quellcode:
liegt, denn es gaht ja auch folgender Code einwandfrei:
Application.ProcessMessages
Delphi-Quellcode:
Natürlich bringt der nix, aber da überschneidet's sich ja auch.
procedure TForm1.Button1Click(Sender: TObject);
var i, j: integer; begin for i := 1 to 5 do begin Application.ProcessMessages; for j := 1 to 10 do Application.ProcessMessages; end; end; |
Re: Überlappendes Application. ProcessMessages macht Unsinn
Naja, es ist schon in Verbindung mit Timern etwas... sagen wir mal "gewöhnungsbedürftig".
Weil:
Delphi-Quellcode:
Also tatsächlich sowas wie eine Rekursion.
procedure onTimer1(irgendwas:TObject);
begin doIrgendwasWasEtwasDauert; Application.ProcessMessages; | --> procedure onTimer2(wasAnderes:TObject); begin doNochWasWasLängerDauert; Application.ProcessMessages; | --> procedure onTimer1(irgendwas:TObject); begin . . . // usw. usf..... end; end; end; Wie man das lösen könnte weiss ich nicht, aber ich habe mein (sehr aktuelles) Problem gleicher Art so gelöst, dass ich in den TimerProcedures einfach kein Application.ProcessMessages benutzte. Fertig ist die Laube :zwinker: gruss, dizzy \edit: Voraussetzung ist natürlich, dass die Bearbeitung innerhalb der Timer1Prozedur bis zum App.ProcessMessages mindestens so lange dauert, wie das Intervall von Timer2, und umgekehrt. Oder die Timer würden asynchron gestartet, oder haben ungleiche Intervalle. Also in den meisten Fällen zumindest geht's in die Hose :D |
Re: Überlappendes Application. ProcessMessages macht Unsinn
@Matze
Dein Code läuft, kein Zweifel, aber ohne Rekursion. Dein ProcessMessages ruft nicht wirklich ein weiteres ProcessMessages auf. In deinem Beispiel wird das ProcessMessages immer der Reihe nach aufgerufen. Du hast nur 2 geschachtelte Schleifen, das ist aber keine Rekursion. Das was ich meinte ist, wenn ein ProcessMessages#1 ein Event deiner Application aufruft, in dem du wiederum auch ProcessMessages#2 nutzt. Dann ist das Event aus ProcessMessages#1 noch nicht abgearbeitet und damit ProcessMessages#1 noch nicht fertig. Ist im Nachhinein auch ein sehr blödes Thema, weiß auch nicht, wie ich es besser beschreiben soll. Naja, Lösung habe ich zwar noch nicht, aber Problem zumindest erkannt und damit 50% erreicht. /edit: @dizzy - Richtig, mir passiert das mit SOCKET-Events, aber selbes Event-Handling wie dein Timer-Bsp. Leider fällt mir nichtmal auf dem Schei**haus eine vernünftige Alternative ein :) |
Re: Überlappendes Application. ProcessMessages macht Unsinn
Das einfachst wäre es wohl Threads zu verwenden. Mit entsprechend niedriger Priorität versehen klauen die dir auch nicht die Bedienbarkeit des Rechners (tpIdle z.B. ist immer wieder schön ;) )
Man kann Multithreading in Schleifen sehr schön mit nem App.ProcessMessages faken, aber es ist unsauber, und wie du ja merkst nicht immer ganz unproblematisch. Bei Threads immer auf Synchronized-Zugriffe auf VCL-Kompos achten, oder CriticalSections einrichten (hab ich nocht nicht gemacht, weiss also nicht wie. Aber zu diesem Thema findet sich sicherlich eine Menge!) gruss, dizzy \edit: Und dass, ohne auf dem Porzellan-Orakel zu sitzen :mrgreen: |
Re: Überlappendes Application. ProcessMessages macht Unsinn
Threads ist so eine Sache. Dazu müsste ich intern viele LOCK-Mechanismen einbauen, die ich mir bisher gespart habe. deswegen auch nur dieses synthetische Multitasking (wie heisst das richtig? ..präemtives MT??).
Ich denke mal der Knackpunkt ist meine Rangehensweise: * Eine Funktion liefert in einer Zeit (0-timeout) ein ergebnis zurück (natürlich mehrfach gleichzeitig ausrufbar). Ich sollte das ganze über Timer lösen (da kommt mir die Galle. zurück zum Pollen). Die Funktion sollte neben dem Wert auch zurückgeben, ob sie überhaupt arbeiten konnte und dann quasi über eine Art CallBack(timer) den eigentlichen Wert/Fehler melden. Ich zerstöre damit aber meinen sauberen und modularen Aufbau meines programmes (ist eine art spezieller TCP-Daten-Server (ca0...1000 clients -> dort scheitere ich auch mit multithreading. kann ja keine 1000 threads anlegen, da beschäftigt sich windows ja noch mehr mit sich selbst :) ) Gibt es da evtl noch eine andere 'Konzeption' ? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz