我有一个数据库应用程序,它非常类似于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。
最佳答案
您的代码是线程安全的,并且在定义的意义上是正确的(我不认为您对该请求ID溢出整数限制)。似乎您知道您将无法终止您没有引用的线程,并且您正在浪费资源。值得补充的是,您将无法取消正在运行的DBMS操作,因为链接的代码实现了同步提取,仅在工作线程中执行,而ADO无法取消这些操作。
不过,有更好的方法可以做到这一点。您可以例如仅创建一个线程(因为每个任务创建一个线程对于频繁执行的任务而言效率低下),具有命令(队列或列表)的集合,并让线程休眠以等待系统事件指示的工作。
或者,也可以代替每个命令一个这样的线程来收集命令(但是在这里,您应该考虑一下应用程序中使用的命令数量)。
而且,您可以实现异步ADO执行(可以将其取消,因此您将中断正在运行的操作并执行另一个操作)。
关于multithreading - 仅处理最后一个TThread任务并丢弃先前的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46130011/