我有一个非常慢的查询,总是让Windows将我的程序标记为“未响应”。我决定创建一个后台工作来执行这个查询,而主线程显示一个GIF。我做了一切,它的工作原理! = D如何在工作线程上线程安全的ClientDataSet?
但是...当我关闭我的窗体时,我得到了一个EInvalidPointer异常,只有当我使用工作线程。
这里是我的代码:
主线程中调用到工作线程
if not TThreadDB.ExecutarThreadDB(cdsSolicitacao,
FConsultaSql,
nil,
tpHigher) then
begin
Exit;
end;
其中: cdsSolicitacao是ClientDataSet的我想在线程之间共享, FConsultaSql字符串(我的查询)
我的线程单位
unit UThreadDB;
interface
uses Classes, DBClient, DB, SysUtils, Variants, JvJCLUtils;
type
TParametros = class
private
FTotal: Integer;
FCampo: array of string;
FTipo: array of TFieldType;
FValor: array of Variant;
public
constructor Create(ACampos: string; ATipos: array of TFieldType; AValores: array of Variant); reintroduce;
end;
TThreadDB = class(TThread)
private
FExecutou: Boolean;
FClientDataSet: TClientDataSet;
FConsultaSQL: string;
FParametros: TParametros;
procedure CarregarDados;
protected
procedure Execute; override;
public
constructor Create(ACreateSuspended: Boolean; AClientDataSet: TClientDataSet; AConsultaSQL: string = '';
AParametros: TParametros = nil); reintroduce;
class function ExecutarThreadDB(AClientDataSet: TClientDataSet; AConsultaSQL: string = '';
AParametros: TParametros = nil; APriority: TThreadPriority = tpNormal): Boolean;
class procedure ExecutarThreadDBParalela(AThreadDB: TThreadDB; AClientDataSet: TClientDataSet;
AConsultaSQL: string = ''; AParametros: TParametros = nil; APriority: TThreadPriority = tpNormal);
end;
implementation
uses
BIBLIO;
{ TThreadDB }
class function TThreadDB.ExecutarThreadDB(AClientDataSet: TClientDataSet; AConsultaSQL: string = '';
AParametros: TParametros = nil; APriority: TThreadPriority = tpNormal): Boolean;
var
lThreadDB: TThreadDB;
begin
lThreadDB := TThreadDB.Create(True, AClientDataSet, AConsultaSQL, AParametros);
try
//lThreadDB.FreeOnTerminate := True;
lThreadDB.Priority := APriority;
lThreadDB.Resume;
lThreadDB.WaitFor;
Result := lThreadDB.FExecutou;
finally
lThreadDB.Terminate;
//lThreadDB := nil;
FreeAndNil(lThreadDB);
end;
end;
class procedure TThreadDB.ExecutarThreadDBParalela(AThreadDB: TThreadDB; AClientDataSet: TClientDataSet;
AConsultaSQL: string = ''; AParametros: TParametros = nil; APriority: TThreadPriority = tpNormal);
begin
AThreadDB := TThreadDB.Create(True, AClientDataSet, AConsultaSQL, AParametros);
AThreadDB.FreeOnTerminate := True;
AThreadDB.Priority := APriority;
AThreadDB.Resume;
end;
procedure TThreadDB.CarregarDados;
var
lIndex: Integer;
begin
FClientDataSet.Close;
try
if (FConsultaSQL <> '') then
begin
FClientDataSet.CommandText := FConsultaSQL;
end;
if (FParametros <> nil) then
begin
for lIndex := 0 to (FParametros.FTotal - 1) do
begin
case FParametros.FTipo[lIndex] of
ftInteger : FClientDataSet.Params.ParamByName(FParametros.FCampo[lindex]).AsInteger := FParametros.FValor[lIndex];
ftString : FClientDataSet.Params.ParamByName(FParametros.FCampo[lindex]).AsString := FParametros.FValor[lIndex];
ftDate : FClientDataSet.Params.ParamByName(FParametros.FCampo[lindex]).AsDate := FParametros.FValor[lIndex];
end;
end;
end;
FClientDataSet.Open;
FExecutou := True;
except
on E: Exception do
begin
Erro('Não foi possível carregar os dados solicitados!' + #13 +
'Classe do erro: ' + E.ClassName + #13 +
'Mensagem: ' + E.Message);
end;
end;
if (FParametros <> nil) then
begin
FreeAndNil(FParametros);
end;
end;
constructor TThreadDB.Create(ACreateSuspended: Boolean; AClientDataSet: TClientDataSet; AConsultaSQL: string = '';
AParametros: TParametros = nil);
begin
inherited Create(ACreateSuspended);
FClientDataSet := AClientDataSet;
FConsultaSQL := AConsultaSQL;
FParametros := AParametros;
FExecutou := False;
end;
procedure TThreadDB.Execute;
begin
CarregarDados;
end;
{ TParametros }
constructor TParametros.Create(ACampos: string; ATipos: array of TFieldType; AValores: array of Variant);
var
lIndex: Integer;
begin
inherited Create;
FTotal := ContaCaracteres(ACampos, ';') + 1;
SetLength(FCampo, FTotal);
SetLength(FTipo, FTotal);
SetLength(FValor, FTotal);
for lIndex := 0 to FTotal - 1 do
begin
FCampo[lIndex] := ExtractDelimited(lIndex + 1, ACampos , [';']);
end;
for lIndex := 0 to FTotal - 1 do
begin
FTipo[lIndex] := ATipos[lIndex];
end;
for lIndex := 0 to FTotal - 1 do
begin
FValor[lIndex] := AValores[lIndex];
end;
end;
end.
我错过了什么想法?
您的大部分代码(这是所有的情况下)。还有一段时间在调试器中弄清楚它到底发生了什么。 –
我编辑了一些信息,可能会使我的问题更清晰 –
这不是您的实际代码,因为您自己不会调用'TThread.Execute';它在线程启动时自动调用。如果你需要帮助你的代码,**发布你的代码**,而不是你为你的帖子发明的东西。不要浪费人们的时间试图解决问题,而不会发布实际的代码。见[mcve]。 –