Einzelnen Beitrag anzeigen

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