刷新线程中的查询

时间:2015-09-22 11:31:41

标签: mysql multithreading performance delphi unidac

我正在使用Delphi XE6和UniDAC以及MySQL

我的DM中有一些TUniQuery组件,我想重复刷新主题,所以我在主窗体中放了一些Timers,在每个定时器中创建一个线程并将查询传递给它以刷新数据:

例如:

 TUpdateThread = class(TThread)
 private
  FQuery : TUniQuery;
  FResultHandle : THandle;
 public
  constructor Create(var Query : TUniQuery; ResultHandle : THandle);
 protected
  procedure Execute; override;
 end;

constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle);
begin
 inherited Create;
 Suspend;
 FQuery := Query;
 FResultHandle := ResultHandle;
 FreeOnTerminate := True;
 Resume;
end;

procedure TUpdateThread.Execute;
var
 Msg : String;
 B : Boolean;
begin
 try
  B := True;
  try
   FQuery.Refresh;
  except
   on E:Exception do
    begin
     B := False;
     Msg := 'Error : ' + #13 + E.Message;
     SendMessage(FResultHandle, MSG_UPDATERESULT, 2, Integer(Msg));
    end;
  end;
 finally
  if B = True then
   SendMessage(FResultHandle, MSG_UPDATERESULT, 1, 1);

  Terminate;
 end;
end;

有时它成功完成但很多次我遇到了一些错误,例如AV或“Net Pack Header ...”错误 或者有时候我的网格(Ehlib DBGrid)有问题,例如绘图行中的错误或...(特别是当我使用DisableControls和EnableControls时) 所有查询都有相同的连接,我认为每个Thread应该有自己的连接,因为所有的定时器间隔都相同,我建议有时刷新查询会中断对方

事实上,我的数据库位于VPS服务器中,并且有一些客户端应用程序,我希望在客户端中安装Live-Tables并重复更新主题

实现这一目标的最佳方法是什么? 如何在没有应用程序挂起的情况下更新我的表格! 有一些组件作为TThreadTimer(或......),主题对这种情况有用吗?!

谢谢......

1 个答案:

答案 0 :(得分:1)

第一个问题在这里:

constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle);
begin
 inherited Create;  // Create with no arguments 
 Suspend;           // means CreateSuspended = false
 FQuery := Query;
 FResultHandle := ResultHandle;
 FreeOnTerminate := True;
 Resume;
end;

在这里,您使用默认构造函数(CreateSuspended = false)创建线程,其中线程立即开始运行。您可以立即调用suspend(已弃用且不应使用),但这仍然是竞争条件,因为您的线程在分配之前可能会或可能不会开始尝试Refresh您的查询。要在挂起状态下创建线程,请使用

的重载构造函数
inherited Create(true);

Resume也已弃用。相反,您应该使用Start;

此外,您将TUniQuery传递给此线程的构造函数。我想,我认为这个查询与主线程具有亲和性 - 这就是说它(可能)是表单上的可视化组件,具有与可视组件的数据绑定,或者由用户或用户以其他方式与之交互接口。

如果是这样的答案,那就是你根本无法做到这一点 - 一个线程无法修改与另一个线程具有亲缘关系的对象。例如,当后台线程同时销毁它们以准备刷新查询内容时,您的界面可能正在从查询中检索记录。当然这会引起各种各样的问题。

简单的解决方案是使用常规计时器并在主线程上同步刷新。如果这需要太长时间,那么您需要完全考虑不同的策略。我们真的没有足够的信息来进一步提出建议。如果网络访问和I / O是瓶颈,那么您可以考虑异步刷新到该线程拥有的单独查询对象,然后将其同步分配给您的视图组件。