AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Object wird manchmal nicht erzeugt

Ein Thema von Hobbycoder · begonnen am 11. Mai 2020 · letzter Beitrag vom 13. Mai 2020
Antwort Antwort
Hobbycoder

Registriert seit: 22. Feb 2017
955 Beiträge
 
#1

Object wird manchmal nicht erzeugt

  Alt 11. Mai 2020, 16:06
Ich habe eine Thread, dem ich Datenbank-Verbindungsparameter übergeben will. Der Einfachheit halber habe ich diese in einer Klasse, und übergeben nur das Object (in meinem Fall DBSettings).
Nun kommt es an einem Client (von anderen erhalte ich keine Fehlermeldungen) immer zwischendurch zu einer EAccessViolation, bei einer Procedure in der Klasse.

Hier mal den entscheidenden Teil des Threads:
Delphi-Quellcode:
unit uSQLThread.SQLSaveCallActivity;

interface

uses System.Classes, System.SysUtils, System.Types, uCallactivity,
  ZAbstractConnection, ZConnection, ZAbstractRODataset, ZDataset, Data.DB, uDBSettings;

type
  TOnThreadFinished=procedure(Sender: TObject) of object;

  TSQLSaveCallActivity=class(TThread)
  private
    FDBSettings: TDBSettings;
    FOnThreadFinished: TOnThreadFinished;
    Ftablename: string;
    Frecordid: string;
    Fagentname: string;
    FIncoming: Integer;
    Fotherpartyphonenumber2: string;
    Flocalpartyphonenumber: string;
    FCallID: Integer;
    Fdevicename: string;
    Fotherpartyname: string;
    Fotherpartyphonenumber: string;
    Fagentguid: TGUID;
    FCallState: string;
    procedure DoThreadFinished;
  published
    property OnThreadFhinished: TOnThreadFinished read FOnThreadFinished write FOnThreadFinished;
  public
    constructor Create(Suspended: Boolean; DBSettings: TDBSettings; Agentguid: TGUID; Agentname: string;
      callid, incoming: Integer; callstate, devicename, localpartyphonenumber, otherpartyphonenumber, recordid,
      otherpartyphonenumber2, otherpartyname, tablename: string);
  protected
    procedure Execute; override;
  end;

const
  DebuggingName = 'SQLSaveCallActivity';

implementation

{ TSQLTemplate }

constructor TSQLSaveCallActivity.Create(Suspended: Boolean; DBSettings: TDBSettings; Agentguid: TGUID; Agentname: string;
      callid, incoming: Integer; callstate, devicename, localpartyphonenumber, otherpartyphonenumber, recordid,
      otherpartyphonenumber2, otherpartyname, tablename: string);
begin
  inherited Create(Suspended);
  FDBSettings:=TDBSettings.Create;
  DBSettings.AssignTo(FDBSettings); //<---Hier springt er noch rein. FDBSettings sollte erzeugt sein. DBSettings wird ja übergeben, und sollte auch vorhanden sein.
  self.Fagentguid:=Agentguid; // Zumal DBSettings vom aufrufenden Thread auch an ganz viele
  self.Fagentname:=Agentname; // andere Threads übergeben wird, und von keinem anderen eine
  self.FCallID:=callid; // Fehlermeldung kommt.
  self.FIncoming:=incoming;
  Self.FCallState:=callstate;
  self.Fdevicename:=devicename;
  self.Flocalpartyphonenumber:=localpartyphonenumber;
  self.Fotherpartyphonenumber:=otherpartyphonenumber;
  self.Frecordid:=recordid;
  self.Fotherpartyphonenumber2:=otherpartyphonenumber2;
  self.Fotherpartyname:=otherpartyname;
  self.Ftablename:=tablename;
end;
Und hier die AssignTo-Procedure der Klasse TDBSettings:
Delphi-Quellcode:
procedure TDBSettings.AssignTo(Dest: TObject);
begin
  if Dest is TDBSettings then
  begin
    (Dest as TDBSettings).Hostname:=self.FHostname; //<---Hier läufts auch noch durch
    (Dest as TDBSettings).Port:=self.FPort;
    (Dest as TDBSettings).UserName:=self.FUserName;
    (Dest as TDBSettings).Password:=self.FPassword;
    (Dest as TDBSettings).Provider:=self.FProvider;
    (Dest as TDBSettings).Databasename:=self.FDatabasename;
  end;
end;

.
.
.
procedure TDBSettings.SetHostname(const Value: string);
begin
  FHostname := Value; //<--Hier kommt dann die Exception.
end;
Auf Grund der Tatsache, dass die Exception im Setter auftritt, und ich in der AssignTo-Procedure nur für das Destination-Object über den Setter gehe, wäre es für mich logisch, dass das Destination-Object, also FDBSettings aus dem Thread nicht existiert. Der dazugehörige Constructor ist aber fehlerfrei durchgelaufen.
Und der Fehler tritt auch nicht bei jedem Thread-Aufruf auf. Der Thread soll lediglich eine einzelne Aktivität in einer DB speichern und beendet sich danach sofort. Manche Aktivitäten werden in de DB gespeichert, andere aber nicht.
Und, es tritt nur bei einem Client auf.

Irgendjemand eine Idee?
Gruß Hobbycoder
Alle sagten: "Das geht nicht.". Dann kam einer, der wusste das nicht, und hat's einfach gemacht.
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.464 Beiträge
 
Delphi 12 Athens
 
#2

AW: Object wird manchmal nicht erzeugt

  Alt 13. Mai 2020, 10:09
Da der Constructor einer Thread-Klasse vollständig im aufrufenden Thread ausgeführt wird, scheint der Fehler nichts mit Threads zu tun zu haben. Ohne Fehlermeldung, Aufrufstack und Quellcode wo TSQLSaveCallActivity tatsächlich erzeugt wird, ist die Fehlerursache nicht sicher einzugrenzen.

Die wahrscheinlichste Ursache ist, beim Aufruf von TSQLSaveCallActivity.Create wird als Parameter DBSettings nil oder ein ungültiger Zeiger z.B. auf ein nicht mehr existierende Instanze von TDBSettings übergeben.
  Mit Zitat antworten Zitat
Hobbycoder

Registriert seit: 22. Feb 2017
955 Beiträge
 
#3

AW: Object wird manchmal nicht erzeugt

  Alt 13. Mai 2020, 11:30
Danke für die Antwort.

Der Thread uSQLThread.SQLSaveCallActivity wird aus einem anderen WorkerThread heraus aufgerufen. Dieser hält die Klasse TDBSettings in dem Object FDBSettings, welches zu beginn des Threads erzeugt und erst am Ende wieder freigegeben wird. Der WorkerThread ist über die gesamte Programmlaufzeit aktiv und wird nicht unterbrochen oder neugestartet.
Weiterhin wird das Object FDBSettings noch an ganz viele andere Threads (ähnlich uSQLThread.SQLSaveCallActivity) übergeben, die andere Datenbank aufgaben erledigen.
Die laufen, auch an dem betroffenen PC, alle fehlerfrei. Von daher kann ich davon ausgehen, dass das Object auch noch existiert wenn es an die Create-Methode von uSQLThread.SQLSaveCallActivity übergeben wird.

Wie gesagt, ich habe das Problem nur an einem von 6 Clients, und kann mir das nicht erklären. Als Fehlermeldung bekomme ich eine EAccessViolation genau im Setter von TDBSettings.Hostname. Ich bekomme lediglich einen BugReport von MadExcept. Ich konnte auch bisher den Fehler bei mir nicht nachstellen oder nachvollziehen. Und, das kann ich den Datenbankeinträgen entnehmen, tritt er über die Programmlaufzeit nicht bei jedem Threadaufruf von uSQLThread.SQLSaveCallActivity auf. Und der ist auch über die gesamte Programmlaufzeit immer der gleiche, weil es dafür nur eine Procedure gibt.

Und doch bin ich mir ganz sicher, dass der Fehler irgendwo bei mir liegen muss. Normalerweise kann man, gerade bei EAccessViolation recht schnell den Punkt finde, wo ein Object fälschlicherweise nicht Erzeugt oder zu früh zerstört wurde. Aber der oben gezeigte Code läßt soch gar keinen Spielraum zu, in dem das passieren könnte. Oder übersehe ich was?
Gruß Hobbycoder
Alle sagten: "Das geht nicht.". Dann kam einer, der wusste das nicht, und hat's einfach gemacht.

Geändert von Hobbycoder (13. Mai 2020 um 12:15 Uhr)
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.275 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Object wird manchmal nicht erzeugt

  Alt 13. Mai 2020, 13:19
Hallo,

procedure TDBSettings.AssignTo(Dest: TObject);
var
sDestClassName: String;
begin
sDestClassName:= Dest.ClassName; // Test, ob hier MadExcept was anzeigt

if Dest is TDBSettings then
Heiko
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.464 Beiträge
 
Delphi 12 Athens
 
#5

AW: Object wird manchmal nicht erzeugt

  Alt 13. Mai 2020, 14:15
"Dest" ist mit sicherer Wahrscheinlichkeit vorhanden, sonst würde der vorherige Test mit "is" bereits fehlschlagen.
Ich vermute das an dieser Stelle "Self" = nil ist oder ungültig.

Auf EAccessViolation kann man sich nur verlassen, wenn auf nil-Pointer zugegriffen wird. Wenn der angesprochene Speicherbereich noch vom Speichermanager verwendet wird und somit das Programm noch das Recht hat auf disen Speicherbereich zuzugreifen, verhält sich das Programm eventuell nur merkwürdig.
  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 22:03 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