![]() |
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:
Ausschnitt aus dem Bugreport
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; // ...
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 |
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) |
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; |
AW: Thread Query keep it simple ABER ...
Doofe Frage: Wofür soll der Thread gut sein, wenn du eh auf den Thread wartest?
|
AW: Thread Query keep it simple ABER ...
Zitat:
Delphi-Quellcode:
Damit der Mainthread weiter laufen kann und die "Reagiert nicht" Meldung nicht kommt, würde ich mal vermuten...
while ( WaitForSingleObject( tQ.Handle, 100 ) = WAIT_TIMEOUT ) and
( A_Halt.Tag = 0 ) do begin Application.ProcessMessages; end; |
AW: Thread Query keep it simple ABER ...
Stand doch im 1. Beitrag.
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz