multithreading - 在线程(Delphi)中打开查询时关闭表单时出错

标签 multithreading delphi

我有一个Query,并在我的Thread中打开它。它可以正常工作,我不想使用Synchronize,因为Synchronize使得主FormQuery未完成提取时不响应。
当关闭显示的Form blow错误时:

系统错误。代码:1400。无效的窗口句柄

type
  TMyThread = class(TThread)
  public
    procedure Execute; override;
    procedure doProc;
  end; { type }
.
.
.
procedure TMyThread.doProc;
begin
  Form1.Query1.Open;
end;

procedure TMyThread.Execute;
begin
  inherited;

  doProc;
end;
.
.
.
procedure TForm1.Button1Click(Sender: TObject);
begin
  thrd := TMyThread.Create(True);
  thrd.FreeOnTerminate := True;
  thrd.Resume;
end;

注意:Query有很多记录。

最佳答案

问题在于,VCL是而不是线程安全的。
为了使查询与其他所有事情并行执行,您必须将其与表单分离。

这意味着您必须使用代码在运行时创建查询:

type
  TMyThread = class(TThread)
  private
    FQuery: TQuery;
    FOnTerminate: TNotifyEvent;
  public
    constructor Create(AQuery: TQuery);
    destructor Destroy; override;
    procedure Execute; override;
    procedure doProc;
    //Add an event handler to do cleanup on termination.
    property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
  end; { type }

constructor TMyThread.Create(AQuery: TQuery);
begin
  inherited Create(True);
  FQuery:= AQuery;
end;

procedure TMyThread.doProc;
begin
  FQuery1.Open;
  Synchronize(
    //anonymous method, use a separate procedure in older Delphi versions
    procedure
    begin
      Form1.Button1.Enabled:= true;  //reenable the button when we're done.
    end
  );
end;

procedure TMyThread.Execute;
begin
  inherited;
  doProc;
end;

destructor TMyThread.Destroy;
begin
  if Assigned(FOnterminate) then FOnTerminate(Self);
  inherited;
end;

在Button1的OnClick中,您将执行以下操作:
type 
  TForm1 = class(TForm)
  private
    AQuery: TQuery;
    ...
  end; {type}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled:= false;  //disable the button so it cannot be started twice.
  thrd.Free;
  AQuery:= TQuery.Create;
  AQuery.SQL.Text:= .....
  thrd := TMyThread.Create(AQuery);
  thrd.OnTerminate:= MyTerminationHandler;
  thrd.FreeOnTerminate:= False;
  thrd.Resume;
end;

最后,将清理代码分配给线程的终止处理程序。
如果销毁线程中的Query,则不能使用FreeOnTerminate:= true,但必须自己释放线程。
procedure TForm1.MyTerminationHandler(Sender: TObject);
begin
  FreeAndNil(AQuery);
end;

警告
仅当您启动1个线程时,此代码才有效。
如果您想多次启动该线程(即同时运行多个查询),则必须创建一个线程数组,例如:
TQueryThreads = record
  MyThread: TMyThread;
  MyQuery: TQuery;
  constructor Create(SQL: string);
end; {record}

TForm1 = class(TForm)
private
  Threads: array of TQueryThreads;
 ....
end; {TForm1}     

请注意,此代码在BDE中不起作用,因为该库不支持同时运行多个查询。
如果要这样做,则必须使用ZEOS或类似的东西。

根据TLama的建议:
我建议将BDE TQuery组件切换为ADO,或下载类似ZEOS components的东西。 BDE非常过时,并且有很多古怪的地方,因为它不再被维护,因此永远不会得到解决。

剩下的唯一问题是,如果关闭Form1,则清理连接。
如果这是您的主要形式,那真的没有关系,因为您的整个应用程序都将崩溃。
如果不是您的主要表单,则需要通过填充OnCanClose处理程序来禁用关闭表单。
TForm1.CanClose(Sender: TObject; var CanClose: boolean);
begin
  CanClose:= thrd.Finished;
end;

关于multithreading - 在线程(Delphi)中打开查询时关闭表单时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23196509/

相关文章:

c++ - 如何编译openCV保证单线程?

c# - 使用多个线程在套接字中发送数据包

c++ - 有没有办法让 GDB 打印一些东西告诉我一行已经执行,而不停止?

c - Ansi C,多线程矩阵乘法

svn - 我如何开始使用子版本 + Delphi?

c++ - 为什么并行化会如此显着地降低性能?

c++ - Delphi 中 C++ NULL 的等效常量是什么?

c++ - 将 Delphi 的字符串转换为 C++ 的 std::string

arrays - 当持有数组的引用计数增加时,如何增加子数组的引用计数?

delphi - 用颜色填充自定义区域