【问题标题】:Process only the last TThread task and discard previous threads仅处理最后一个 TThread 任务并丢弃以前的线程
【发布时间】:2017-09-09 11:08:36
【问题描述】:

我有一个数据库应用程序,它异步获取数据库记录集,非常类似于Threaded Delphi ADO Query

每次用户单击刷新时,都会创建一个新的TDBThread 以获取记录集。

当这种情况发生时,我想丢弃所有以前的请求,只处理最后一个。

所以我创建了一个名为FRequestID 的类字段,每次发出请求时我都会递增该字段。我不会尝试取消/中止之前的请求,也不会继续引用创建的线程。

procedure TForm1.RefreshClick(Sender: TObject);
var
  T: TDBThread;
begin
  Inc(FRequestID);

  T := TDBThread.Create(True); // Suspended
  T.FreeOnTerminate := True;
  T.RequestID := FRequestID;
  T.SQL := 'select * from mytable where ...';  
  T.OnTerminate := DBThreadTerminate;
  T.Resume;
end;

在终止时,我检查线程 RequestID 是否是最后一个 FRequestID,然后我才处理请求。

procedure TForm1.DBThreadTerminate(Sender: TObject);
var
  T: TDBThread;
begin
  T := TDBThread(Sender);
  if FRequestID = T.RequestID then
  begin  
    Memo1.Lines.Add('*** Thread terminated ok ' + IntToStr(T.RequestID));
    MainDS.RecordSet := T.RecordSet;
  end
  else
    Memo1.Lines.Add('Thread discarded: ' + IntToStr(T.RequestID ));
end;

我的问题是这种方法是否正确(并且是线程安全的),是否有更好的方法来仅处理最后一个请求?

注意:我使用的是 Delphi 7。

【问题讨论】:

  • 我会以不同的方式处理这个问题。当线程正在执行它的工作时禁用刷新按钮。那么就不需要多个线程,不需要任何可能不是线程安全访问的整数。也许将 TAction 链接到按钮,如果 DBThread 正在运行,请使用 OnUpdate 事件将其禁用。
  • @Nil,谢谢,不管是点击按钮还是附加TAction。您不能拒绝用户在 DBThread 运行时点击刷新或执行新查询(例如使用新的搜索条件)。至少不在我的程序中。
  • 我认为你需要实现其中的一些stackoverflow.com/questions/4044855/…

标签: multithreading delphi delphi-7


【解决方案1】:

按照您定义的含义,您的代码是线程安全且正确的(我没有指望您溢出了该请求 ID 的整数限制)。似乎您知道您将无法终止您没有参考的线程并且您正在浪费资源。值得补充的是,您无法取消正在运行的 DBMS 操作,因为您链接的代码实现了同步提取,只是在工作线程中执行,而 ADO 无法取消这些操作。

虽然有更好的方法来做到这一点。你可以例如只创建一个线程(因为每个任务创建一个线程对于频繁的任务来说效率低下),拥有一组命令(队列或列表),并让线程睡眠等待系统事件发出的工作信号.

或者不是命令收集每个命令一个这样的线程(但在这里您应该考虑应用程序中使用的命令数量)。

你可以实现异步ADO执行(可以取消,所以你会中断正在运行的操作并执行另一个)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    相关资源
    最近更新 更多