AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Delphi TOracleQuery Threaded --> Wann Query-Objekt freigeben?
Thema durchsuchen
Ansicht
Themen-Optionen

TOracleQuery Threaded --> Wann Query-Objekt freigeben?

Offene Frage von "sirius"
Ein Thema von sirius · begonnen am 4. Mai 2010 · letzter Beitrag vom 6. Mai 2010
Antwort Antwort
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#1

TOracleQuery Threaded --> Wann Query-Objekt freigeben?

  Alt 4. Mai 2010, 18:27
Datenbank: Oracle • Version: 11 • Zugriff über: DOA (4.1.1 für D7)
So, nach mehrere Tagen glaube ich zu behaupten, mein Problem/Fehler eingegrenzt zu haben. Und ich vermute die Fehlerursache bei TOracleQuery bzw. dessen Anwendung.

Was macht das Programm
Das Programm habe ich soweit reduziert, wie es ging.
Jetzt ist nur noch ein Timer enthalten, der recht oft ein TOraclequery mit einer einfachen Select-Abfrage erstellt und ausführt. Das ganze im Threaded Mode (zugehörige OracleSession ist auch threadsafe eingestellt)
Im Original-Code ist der Timer eigentlich ein OracleEvent (habe ich nur zum Test durch einen Timer ersetzt)


wichtigstes Fehlersymptom
Programm ist plötzlich nicht mehr bedienbar (kann im ersten Query passieren, oder erst nach 20 Minuten (bei durchschnittlich 1 Query / 5sek). Es läuift aber noch und im TaskManager wird konstant "wird ausgeführt" angezeigt. Besagtes Oracleevent löst auch nach wie vor (asynchron) aus. Kann man einen Breakpoint reinsetzen. An allen anderen Stellen im Code hilft ein Breakpoint nicht.
Es sieht also aus, wie ein Deadlock (ich vermute mal mit MsgWaitForMultipleObjects; müsste man aber nochmal nachbauen)

wann tritt das Problem auf
Der Deadlock tritt anscheinend auf, wenn ich das Query-Objekt freigebe. Ein Problem tritt genauso auf (allerdings als Exception), wenn ich das Query-Objekt erneut nutze ohne es vorher freizugeben (ist dann als Feld der Klasse deklariert). Ich warte allerdings immer QueryThreadFinished ab und sende von da sogar noch eine Message via PostMessage und erst hier wird die Freigabe gestartet, oder das Objekt zur erneuten Nutzung freigegeben.

wichtiger Code
Delphi-Quellcode:
procedure TMainForm.LoadIPList; //wird regelmäßig durch ein Event oder Timer ausgelöst
var Query:TOracleQuery;
begin
  if FQueryCount=0 then
  begin

   
    Log('LoadIPList');
    FTempIPList:=TIPList.Create(true);

    Query:=TORacleQuery.Create(self);
    Query.Session:=ORacleSession;
    Query.Threaded:=true;
    Query.ThreadSynchronized:=true;
    Query.OnThreadFinished:=QueryThreadFinished;
    Query.OnThreadRecord:=QueryThreadRecord;
    Query.OnThreadError:=QueryThreadError;
    Query.SQLW:='Select distinct SrcIP as x from dbt_Traffic';
    Query.Execute;
    inc(FQueryCount);

  end;
end;



procedure TMainForm.QueryThreadFinished(Query: TOracleQuery);
begin
  log('QueryThreadFinished');
  postmessage(handle,CM_QueryFree,0,integer(Query));
end;


procedure TMainForm.CMQueryFree(var msg: TMessage); //message CM_QueryFree;
var del:boolean;
    c:integer;
begin
  if FQueryCount>0 then dec(FQueryCount);
  
  //hier habe ich mit einer Schleife und sleep auch schon auf ThreadisRunning und Status=qsIdle gewartet, bringt auch nichts
  
  TObject(msg.lparam).free;
  Log('QueryFree $'+inttohex(msg.LParam,8)+' '+inttostr(FQueryCount));
end;

//QueryThreadRecord kann man komplett auskommentieren, der Fehler erscheint trotzdem.
//das Query kann ich auch als Feld der Klasse deklariern. Da müsste ich es nicht freigeben, allerdings kommt dann ein fehler bei LoadIPList (wahrscheinlich, wenn es sonst einen Deadlock gegeben hätte)
Was habe ich jetzt gemacht
Ich habe eine TObjectList, in der ich mir die Query-Objekte merke und lösche in LoadIPList dann immer das vorletzte. Bisher ohne Probleme. Aber das kann ja nicht die Lösung sein. Gibt es da nicht etwas besseres? Ich habe damals leider nicht die Sourcen mitgekauft um da mal nachzusehen.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
909 Beiträge
 
Delphi 10.3 Rio
 
#2

Re: TOracleQuery Threaded --> Wann Query-Objekt freigeben

  Alt 5. Mai 2010, 09:08
Hi Sirius,

leider kenne ich TORacleQuery nicht, aber beim Lesen Deines Posts habe ich mir die Frage gestellt warum DU das so gelöst hast.

Ich hoffe mal das :
Query.Execute; sich bei TOracleQuery auf Execute eines TThreads bezieht und nicht dem Execute einer TQuery, in dem Fall müßte es nämlich Query.Active := true; heissen weil Du ein "Select" SQL hast.
Ich gehe jetzt mal ganz stark von Execute eines TThreads aus, dabei würde mich interessieren wann das Programm an die Zeile :
inc(FQueryCount); kommt ?! Werden vorher die Events OnThreadRecord, OnThreadFinished aufgerufen ?
Wenn ja, kannst Du nach dem Execute die Query einfach freigeben.

Dein jetziger Code mit der FQueryCount=0 "Sperre" ist nicht wirklich "Thread-Safe",
gerade wenn Du das ganze nachher aus einem DB-Event aus aufrufen möchtest,
solltest Du das ganze besser mit einer TCriticalSection schützen.

Ist Deine Funktion "Log" den Thread-Safe ? Alternativ könntest Du erstmal "OutputDebugSTring" verwenden.

Wenn das Oracle Query-Object auf einem Thread aufbaut, vielleicht gibt es sogar die Eigenschaft "FreeOnTerminate",
dann bis Du aus der Sache fein raus.

Aber ich denke die meisten brauchen um Dir zu helfen ein wenig mehr imput was "TOracleQuery" angeht,

Greetz Data
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#3

Re: TOracleQuery Threaded --> Wann Query-Objekt freigeben

  Alt 5. Mai 2010, 16:26
Zitat von DataCool:
Hi Sirius,
leider kenne ich TORacleQuery nicht
, aber beim Lesen Deines Posts habe ich mir die Frage gestellt warum DU das so gelöst hast.
Ich hoffe mal das :
Query.Execute; sich bei TOracleQuery auf Execute eines TThreads bezieht
Nein, das ist was bei anderen Datenbankkomponenten "Open" und "ExecSQL" ist. Hier ist nur beides in einem, es gibt kein open. Hier liefert auch Execute ein Recordset zurück.

Der Thread wird in der Komponente intern gestartet, den sehe ich von außen nicht und hab auch wegen fehlenden Sourcen keinen Einfluss darauf.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#4

Re: TOracleQuery Threaded --> Wann Query-Objekt freigeben

  Alt 6. Mai 2010, 15:40
So, ich habe rausgefunden, dass das Programm bei der Freigabe von TORacleQuery auch den internen Thread freigebt und vorher noch mit TThread.Waitfor auf das Ende wartet. Allerdings wurde der Thread kurz zuvor mit suspend schlafen gelegt (warum weis ich nicht).

Hier mal der Code zum selber testen:
Delphi-Quellcode:
//ein Doppelklick aufs Memo würde den Test starten

type
  TForm1 = class(TForm)
    OracleSession1: TOracleSession; //Verbindung im OI eingestellt und connected auf true; threadsafe auch auf True
    Memo1: TMemo;
    procedure OracleQueryThreadError(Sender: TOracleQuery;
      ErrorCode: Integer; const ErrorMessage: String);
    procedure OracleQueryThreadExecuted(Sender: TOracleQuery);
    procedure OracleQueryThreadFinished(Sender: TOracleQuery);
    procedure OracleQueryThreadRecord(Sender: TOracleQuery);
    procedure Memo1DblClick(Sender: TObject);
  private
    { Private-Deklarationen }
    FRecorded:Integer;
    procedure WMUser(var Msg:TMessage); message WM_User;
    procedure StartQuery;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.OracleQueryThreadError(Sender: TOracleQuery;
  ErrorCode: Integer; const ErrorMessage: String);
begin
  memo1.Lines.add('Error: '+inttostr(ErrorCode)+' '+ErrorMessage);
end;

procedure TForm1.OracleQueryThreadExecuted(Sender: TOracleQuery);
begin
  memo1.lines.add('Executed');
end;

procedure TForm1.OracleQueryThreadFinished(Sender: TOracleQuery);
begin
  memo1.lines.add('Finished - '+inttostr(FRecorded)+' Records');
  postmessage(handle,WM_User,0,integer(Sender)); //start new
end;

procedure TForm1.OracleQueryThreadRecord(Sender: TOracleQuery);
begin
  inc(FRecorded);
end;

procedure TForm1.Memo1DblClick(Sender: TObject);
begin
  StartQuery;
end;

procedure TForm1.WMUser(var Msg: TMessage);
var OracleQuery:TOracleQuery;
begin
  OracleQuery:=TOracleQuery(msg.LParam);
  //while OracleQuery.ThreadIsRunning do sleep(1); //mit der Zeile passiert es deutlich seltener, aber das ist ja auch keine Lösung
  OracleQuery.Free;
  StartQuery;
end;

procedure TForm1.StartQuery;
var OracleQuery:TOracleQuery;
begin
  FRecorded:=0;
  OracleQuery:=TOracleQuery.Create(self);
  OracleQuery.OnThreadExecuted:=self.OracleQueryThreadExecuted;
  OracleQuery.OnThreadRecord:=self.OracleQueryThreadRecord;
  OracleQuery.OnThreadFinished:=self.OracleQueryThreadFinished;
  OracleQuery.OnThreadError:=self.OracleQueryThreadError;
  OracleQuery.Threaded:=true;
  OracleQuery.ThreadSynchronized:=true;
  OracleQuery.Session:=OracleSession1;
  ORacleQuery.SQLW:='Select * from all_users';
  OracleQuery.Execute;
end;

end.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  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 16:53 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