![]() |
OnFinish --> FreeAndNil --> Exception
Hallo,
ich versuche mich soweit es geht mittlerweile an der asynchronen Programmierung. D.h. nicht mehr "Tue etwas - *warten* - Auswerten" sondern "Tue etwas, und wenn Du fertig bist, rufe die-und-die Prozedur zurück". Ich habe einen ClientSocket der mit einem Netzwerkgerät kommuniziert. Sobald er eine Antwort erhalten hat, speichert er das Ergebnis, trennt die Verbindung und kann dann freigegeben werden (ich habe ja jetzt meine Infos und brauche den ClientSocket nun nicht mehr).
Delphi-Quellcode:
procedure TFoo.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin ResultText := 'Getrennt von ' + Socket.RemoteAddress; NotifyFinish; end; procedure TFoo.NotifyFinish; begin if assigned(OnFinish) then begin OnFinish(Self); end; end;
Delphi-Quellcode:
Der ClientSocket agiert also unabhängig vom Hauptprogramm (bzw. "form2"), und löst auch brav TForm2.SendFinished aus, die Infos werden korrekt im Memo angezeigt.
procedure TForm2.SendFinished(Sender: TObject);
var cs: TFoo; begin if Sender.InheritsFrom(TFoo) then begin cs := TFoo(Sender); Memo1.Lines.Add('ResultText: ' + cs.ResultText); Memo1.Lines.Add('ResultData: ' + cs.ResultData); Memo1.Lines.Add('Result: ' + BoolToStr(cs.Success, True)); FreeAndNil(cs); end; end; Im Step-By-Step Debugging bin ich nun nach dem Disconnect mit der Zeile "NotifyFinish" durch, und IN der "end;" Zeile von ClientSocket1Disconnect schmeißt er mir nun die Exception um die Ohren. Die Fehlermeldung Socket 10038 die ich erhalte bedeutet letzt endlich, dass Ich/Windows auf einen Socket zugreife, den es nicht mehr im RAM gibt. Ist ja eigentlich auch klar, ich habe den kompletten ClientSocket ja auch eben mit FreeAndNil freigegeben... Die Ursache für dieses eigentliche Problem ist mit ja generell bekannt. In der ParameterListe von ClientSocket1Disconnect steht ja ein Verweis auf "Socket: TCustomWinSocket", und nach Ende dieser Prozedur wird entweder mein Hauptobjekt, oder zumindest der übergebene Socket nochmal(?) von der Garbage-Collection oder sonstweshalb freigegeben oder was auch immer. Die Frage ist nun, wie macht man es richtig? Ich einem früheren Thema von mir habe ich ja beigebracht bekommen, dass ein Objekt sich nicht selbst freigeben kann/darf/soll. Also muss ich über ein Event der übergeordneten Komponente mitteilen, dass diese Komponente nun ihre Arbeit beendet hat und freigegeben werden kann. Aus Prozeduren heraus, die mehr als nur "Sender: TObject;" als Parameter haben, darf man das scheinbar nicht? Eine andere private Prozedur aufrufen, die die übergeordnete Komponente zum freigeben benachrichtigt bringt ja auch nichts, weil ich nach Abwicklung dieser Prozedur ja wieder bzw. immernoch in ClientSocket1Disconnect bin, und das selbe Problem gerade wieder besteht. Wie rufe ich nun die Benachrichtigung auf, ohne noch einen auf den Stack draufzulegen? Die einzige Möglichkeit die mir einfällt, wäre bei ClientSocket1Disconnect einen Timer der selben Komponente zu stellen, der nach 1ms triggert und dann das OnFinish auslöst. Dann wäre zumindest das Problem mit der Socket-Exception gelöst (falls es klappt). Aber ist das die richtige und/oder elegante Weise? Kann ich mir nicht vorstellen... |
AW: OnFinish --> FreeAndNil --> Exception
Ein Objekt im Eventhandling freigeben ist, sagen wir mal so, "mehr als Mutig".
I.d.R. wird es krachen, da beim "Rückabarbeiten" des Event-Kette irgendwo noch auf Eigenschaften des schon freigegebenen Objektes zugegriffen wird. |
AW: OnFinish --> FreeAndNil --> Exception
Code:
Ja, das ist richtig, ich hoffe ich konnte im ersten Beitrag vermitteln, dass ich selbst (schmerzhaft) zu dieser Erkenntnis gelangt bin.
I.d.R. wird es krachen, da beim "Rückabarbeiten" des Event-Kette irgendwo noch auf Eigenschaften des schon freigegebenen Objektes zugegriffen wird.
Die Frage ist halt: Wie macht man es richtig? Weil wenn man nicht Ereignis-bezogen freigeben kann ("Ich bin fertig - lösch mich") muss man ja in zeitlichen Intervallen prüfen "Wenn fertig, dann löschen". Das muss doch auch anders gehen, oder irre ich mich? Edit: Ich habe es jetzt tatsächlich so "gelöst", dass ClientSocket1Disconnect einen Timer startet, der nach 1 ms das NotifyFinish aufruft. Gut - Nicht Gut? Kann es sein, dass innerhalb der 1 ms der ClientSocket immer noch nicht fertig "verarbeitet" ist, obwohl nach dem Stellen des Timers keine Programmierzeile mehr ist, und es deshalb unerwartete Probleme gibt? |
AW: OnFinish --> FreeAndNil --> Exception
Timer sind in 99% der Fälle nicht gut. in der Regel sollte der, der eine Klasse erzeugt diese auch wieder freigeben. Kannst du nicht "der" ein Event schicken dass diese das macht?
|
AW: OnFinish --> FreeAndNil --> Exception
Zitat:
Bei ClientSocket1Disconnect kann ich das ja nicht tun. Woher weiß ich denn, wann das Event ausgelöst werden soll, wenn nicht über dieses Ereignis? Das einzige, ansatzweise "professionelle" Verfahren was ich mir hierfür vorstellen könnte, ist, dass SendFinished NICHT FreeAndNil aufruft, sondern den Sender (cs) merkt (z.B. in einer ComponentList speichern). Eine -wie auch immer aufzurufende- (wieder das Kernproblem!) Prozedur schaut nach, ob in der ComponentList Einträge stehen und löscht diese Komponente dann mit FreeAndNil. Alternativ bekommt TFoo einfach eine Boolean-Variable, ob Fertig oder nicht, und TForm2 prüft dann halt die Boolean-Variable, und löscht die Komponente dann. Trotzdem muss diese "Löschroutine" von TForm2 über einen Timer oder sporadisch im Rahmen anderer Prozeduren aufgerufen werden, damit die Komponenten TFoo freigegeben werden können. Wird wohl so klappen, aber ob das dem Konzept der Asynchronen Programmierung entspricht (ernstgemeinte Frage)? |
AW: OnFinish --> FreeAndNil --> Exception
Hallo,
also prinzipiell läßt sich das über mehrere Ansätze lösen. 1. Ansatz - dem Objekt sagen es soll sich später freigeben --> Das Objeckt soll sich abarbeiten und den selber Freigeben. Aber nur wenn man es dazu auffordert (DoTerminate := TRUE;) 2. Ansatz - entkoppplung "der Botschaft" vom Objekt-Kontext a) PostMessage mit WM_MEINE_MESSAGE an z.B. Form
Delphi-Quellcode:
b) Anonymer Thread
const WM_MEINE_MESSAGE = WM_USER +1;
//... TForm2. procedure WMMeineMessage(var Message: TMessage);message WM_MEINE_MESSAGE; //...
Delphi-Quellcode:
Vielleicht bringt dich das ja weiter
procedure ExecuteInAnonymThread(AThreadProc: TProc; ADoSyncronized: Boolean; ADelay: Int64);
begin TThread.CreateAnonymousThread( procedure begin Sleep(ADelay); if ADoSyncronized then begin TThread.Synchronize(nil, procedure begin AThreadProc; end); end else begin AThreadProc; end; end).Start; end; Gruß, Chris |
AW: OnFinish --> FreeAndNil --> Exception
Ich würde mir mal anschauen wie das
![]() Die benutze ich an zig Stellen, und das arbeitet sehr zuverlässig mit und ohne Threads. Rollo |
AW: OnFinish --> FreeAndNil --> Exception
Delphi-Quellcode:
Procedure QueueMethod(aThreadMethod:TThreadMethod);
Begin // Abgeschaut aus UNIT FMX.FORMS // procedure ReleaseForm(const AForm: TCommonCustomForm); // Wir müssen das immer so machen wie die das dort auch machen. // Unter der Annahme dass die FMX Bibliotheken fehlerfrei sind.... {$IFDEF ANDRODID} TThread.CreateAnonymousThread( Procedure Begin TThread.CurrentThread.Queue(nil,AthreadMethod); end; ); {$ELSE} TThread.CurrentThread.ForceQueue(nil,aThreadMethod); {$ENDIF} end; TThread.CurrentThread.ForceQueue(nil,aThreadMethod ); Macht unter Windows im Hauptthread, dass die Methode erst nach dem "abspielen" aller anderen Messages aufgerufen wird... Dieser Mechanismus reagiert also evtl. unerwünscht auf Application.processmessages... Denn innerhalb dieses Aufrufs würde die Methode auch ausgeführt... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:13 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