Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Thread Query keep it simple ABER ... (https://www.delphipraxis.net/184599-thread-query-keep-simple-aber.html)

cramer 8. Apr 2015 19:41

Delphi-Version: 2006

Thread Query keep it simple ABER ...
 
Hallo,
mein 1. Versuch, den Querypart in einem Thread laufen zu lassen, um bei langen Abfragen
1. die Abfrage beenden zu können und
2. "die Anwendung reagiert nicht mehr" zu vermeiden.

Das ganze läuft mit IBObjects Komponenten und das Ergebnis wird in einem cxGrid angezeigt.

DB -> TiboDatabase -> TiboTransaction -> TiboQuery -> TDataSource -> TcxGridDBTableView

Es funktioniert alles ohne Probleme. Nur beim Programmende gibt immer Fehler 1400 "Ungültiges Fensterhandle", wenn vorher eine Query über den Thread gelaufen ist.

Bleibt möglicherweise die Verbindung "FQuery := aQuery", nach dem der Thread weg ist, bestehen und zeigt ins Nirvana?
Code:
type
   TiboqThread = class( TThread )
   private
      FQuery    : TiboQuery;
      FErrorCode : integer;
      FErrorText : string;
   public
      constructor Create( AQuery : TiboQuery );
      destructor Destroy; override;
      procedure  Execute; override;
      procedure  ClearError;
      procedure  SendError;
   end; { type }

constructor TiboQThread.Create( aQuery : TiboQuery );
begin
   inherited Create( True );
   FQuery := aQuery;
end;

procedure TiboQThread.ClearError;
begin
   LastErrCode := 0;
   LastErrText := '';
end;

procedure TiboQThread.SendError;
begin
   LastErrCode := FErrorCode;
   LastErrText := FErrorText;
end;

procedure TiboQThread.Execute;
var i : integer;
begin
   inherited;
   try
      Synchronize( ClearError );
      FQuery.Open;
   except
      on E : Exception do begin
         FErrorCode := 4313; // ERROR_DATABASE_FAILURE;
         FErrorText := 'Query-Thread:' + E.ClassName + ' - ' + E.Message;
         Synchronize( SendError );
      end;
   end;
end;

destructor TiboQThread.Destroy;
begin
   FQuery := nil;
   inherited;
end;

// Main
// ...
IBQ1.Active := False;
IBQ1.SQL.Text := tmpSql;
// IBQ1.Active := True;
// Try it via Thread
tQ := TiboqThread.create( IBQ1 );
tQ.FreeOnTerminate := False;
tQ.Resume;
while ( WaitForSingleObject( tQ.Handle, 100 ) = WAIT_TIMEOUT ) and
      ( A_Halt.Tag = 0 )
do begin
   Application.ProcessMessages;
end;
if LastErrCode = 0 then begin
   // Alles OK
end else begin
   FehlerAusgabe1( LastErrText );
end;
tQ.Free;
// ...
Ausschnitt aus dem Bugreport
Code:
exception class  : EOSError
exception message : System Error. Code: 1400. Ungültiges Fensterhandle.

main thread ($8b0):
0045ff80 +070 TEST.exe SysUtils                       RaiseLastOSError
0045ff09 +005 TEST.exe SysUtils                       RaiseLastOSError
004bb551 +031 TEST.exe Controls                       TWinControl.DestroyWindowHandle
004b9e0b +05f TEST.exe Controls                       TWinControl.Destroy
004c0ba5 +01d TEST.exe Controls                       TCustomControl.Destroy
0054b8e4 +020 TEST.exe cxControls            1987  +2 TcxSizeGrip.Destroy
00404710 +008 TEST.exe System                  48  +0 TObject.Free
00460630 +008 TEST.exe SysUtils                       FreeAndNil
0054c60d +021 TEST.exe cxControls            2507  +5 TcxControl.DestroyScrollBars
0054bc65 +019 TEST.exe cxControls            2127  +2 TcxControl.Destroy
0070423c +01c TEST.exe cxGridCustomView      4296  +3 TcxGridSite.Destroy
00404710 +008 TEST.exe System                  48  +0 TObject.Free
00460630 +008 TEST.exe SysUtils                       FreeAndNil
00706c6e +006 TEST.exe cxGridCustomView      6071  +1 TcxCustomGridViewInfo.DestroySite
00706a4c +010 TEST.exe cxGridCustomView      5975  +1 TcxCustomGridViewInfo.Destroy
006f2b24 +020 TEST.exe cxGridCustomTableView 12424  +2 TcxCustomGridTableViewInfo.Destroy

himitsu 8. Apr 2015 19:59

AW: Thread Query keep it simple ABER ...
 
Die VCL ist nicht threadsave.
Wenn also das Grid auf die Änderungen des Query reagiert, dann kann das nette Effekte haben.

* Query synchronisiert abhängen, solange der Thread etwas macht
* oder das Grid sperren (synchronisiertes DisableControls), solange der Thread etwas macht, und hoffen das Grid beachtet das wirklich komplett.

PS: Ich hoffe deine Connection ist auch threadsave. (vermutlich nicht, also nicht, daß gleichzeitig in einem anderen Thread/Hauptthread was damit gemacht wird)

cramer 9. Apr 2015 09:58

AW: Thread Query keep it simple ABER ...
 
Danke für den Tip, ich warte ja in dem HauptThread auf das Ende des QueryThreads und mache dort zumindest nix Vordergründiges.

Es scheint aber so zu sein, wie Du es vermutet hast, das Grid reagiert im Hintergrund auf Änderungen in der Query.
:thumb:
Ich habe es daher vorher getrennt und hinterher wieder verbunden.
Der Spuk mit dem Error-1400 hat zumindest bei meinen Tests jetzt ein Ende gefunden.
Code:
// --------------
   ibds1.DataSet := nil;
   gridV1.DataController.DataSource := nil;
// --------------
tQ := TiboqThread.create( IBQ1 );
tQ.FreeOnTerminate := true;
tQ.Resume;
while ( WaitForSingleObject( tQ.Handle, 100 ) = WAIT_TIMEOUT ) and
      ( A_Halt.Tag = 0 )
do begin
  Application.ProcessMessages;
end;
if LastErrCode = 0 then begin
   // Alles OK
// --------------
   ibds1.DataSet := IBQ1;
   gridV1.DataController.DataSource := IBDS1;
// --------------
   GridV1.ClearItems;
   GridV1.DataController.CreateAllItems;
end else begin
   FehlerAusgabe1( LastErrText );
end;
tQ.Free;

Neutral General 9. Apr 2015 10:15

AW: Thread Query keep it simple ABER ...
 
Doofe Frage: Wofür soll der Thread gut sein, wenn du eh auf den Thread wartest?

Mavarik 9. Apr 2015 11:28

AW: Thread Query keep it simple ABER ...
 
Zitat:

Zitat von Neutral General (Beitrag 1296877)
Doofe Frage: Wofür soll der Thread gut sein, wenn du eh auf den Thread wartest?

Delphi-Quellcode:
while ( WaitForSingleObject( tQ.Handle, 100 ) = WAIT_TIMEOUT ) and
       ( A_Halt.Tag = 0 )
 do begin
   Application.ProcessMessages;
 end;
Damit der Mainthread weiter laufen kann und die "Reagiert nicht" Meldung nicht kommt, würde ich mal vermuten...

cramer 10. Apr 2015 10:00

AW: Thread Query keep it simple ABER ...
 
Stand doch im 1. Beitrag.
Zitat:

Zitat von cramer (Beitrag 1296798)
Hallo,
mein 1. Versuch, den Querypart in einem Thread laufen zu lassen, um bei langen Abfragen
1. die Abfrage beenden zu können und
2. "die Anwendung reagiert nicht mehr" zu vermeiden.



Alle Zeitangaben in WEZ +1. Es ist jetzt 19:56 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