AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi OnFinish --> FreeAndNil --> Exception
Thema durchsuchen
Ansicht
Themen-Optionen

OnFinish --> FreeAndNil --> Exception

Ein Thema von berens · begonnen am 16. Okt 2018 · letzter Beitrag vom 17. Okt 2018
Antwort Antwort
berens

Registriert seit: 3. Sep 2004
434 Beiträge
 
Delphi 10.4 Sydney
 
#1

OnFinish --> FreeAndNil --> Exception

  Alt 16. Okt 2018, 12:03
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:
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;
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.

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...
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.192 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: OnFinish --> FreeAndNil --> Exception

  Alt 16. Okt 2018, 12:28
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.
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
berens

Registriert seit: 3. Sep 2004
434 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: OnFinish --> FreeAndNil --> Exception

  Alt 16. Okt 2018, 12:36
Code:
I.d.R. wird es krachen, da beim "Rückabarbeiten" des Event-Kette irgendwo noch auf Eigenschaften des schon freigegebenen Objektes zugegriffen wird.
Ja, das ist richtig, ich hoffe ich konnte im ersten Beitrag vermitteln, dass ich selbst (schmerzhaft) zu dieser Erkenntnis gelangt bin.

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?
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit

Geändert von berens (16. Okt 2018 um 12:40 Uhr)
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.442 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: OnFinish --> FreeAndNil --> Exception

  Alt 16. Okt 2018, 12:51
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?
  Mit Zitat antworten Zitat
berens

Registriert seit: 3. Sep 2004
434 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: OnFinish --> FreeAndNil --> Exception

  Alt 16. Okt 2018, 13:26
Zitat:
Kannst du nicht "der" ein Event schicken dass diese das macht?
Ja, aber wann und wie löse ich dieses Event aus? Das ist ja die Kernfrage.

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)?
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit
  Mit Zitat antworten Zitat
Benutzerbild von ChrisE
ChrisE

Registriert seit: 15. Feb 2006
Ort: Hechingen
504 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#6

AW: OnFinish --> FreeAndNil --> Exception

  Alt 16. Okt 2018, 13:33
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:
const WM_MEINE_MESSAGE = WM_USER +1;
//...
TForm2.
procedure WMMeineMessage(var Message: TMessage);message WM_MEINE_MESSAGE;
//...
b) Anonymer Thread
Delphi-Quellcode:
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;
Vielleicht bringt dich das ja weiter

Gruß, Chris
Christian E.
Es gibt 10 Arten von Menschen, die die Binär lesen können und die die es nicht können

Delphi programming rules
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.067 Beiträge
 
Delphi 12 Athens
 
#7

AW: OnFinish --> FreeAndNil --> Exception

  Alt 17. Okt 2018, 13:41
Ich würde mir mal anschauen wie das TMessage und TMessageManager gelöst haben.

Die benutze ich an zig Stellen, und das arbeitet sehr zuverlässig mit und ohne Threads.

Rollo
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.925 Beiträge
 
Delphi 12 Athens
 
#8

AW: OnFinish --> FreeAndNil --> Exception

  Alt 17. Okt 2018, 17:39
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...
Andreas
Monads? Wtf are Monads?

Geändert von QuickAndDirty (17. Okt 2018 um 17:44 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:11 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