【发布时间】:2017-09-16 01:47:44
【问题描述】:
我有一个非常慢的查询,总是让 Windows 将我的程序标记为无响应。我决定创建一个后台工作者来执行这个查询,而主线程显示一个 GIF。我做了一切,它的工作原理! =D
但是...当我关闭我的表单时,我得到了一个 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;它在线程启动时自动调用。如果您需要代码方面的帮助,请发布您的代码,而不是您为帖子发明的东西。不要在不发布实际代码的情况下浪费人们的时间来尝试解决问题。见minimal reproducible example。 -
就像 Ken 所说的,您发布的代码与您所描述的并不完全相符。这如何让您的主线程为 gif 设置动画?来自主线程的调用正在等待您的 DbThread,没有任何并行。这应该阻塞主线程,不是吗?那么如何关闭表单并获取描述的 EInvalidPointerException 呢?
-
至于在线程之间共享 ClientDataset,这可能会导致您的异常。 ExecutarThreadDBParalela 让线程使用对 ClientDataset 的引用进行工作,该引用可能在您的线程没有注意到的情况下被破坏。而且您的设计不会让运行 DBThreads 的主线程关闭。
标签: multithreading delphi