Delphi TTask WaitForAll 与同步

HJa*_*Jay 2 delphi multithreading

我只有有限的线程经验。我想并行读取一些基本的数据库表,我需要等到所有表都被读取后才能合理地进行程序。在这方面,阻塞主线程对我来说是可以的。

此代码(简化)工作正常:

procedure ReadDBMultiThread;
  var ATasks : Array of ITask;
begin
  SetLength(ATasks, 3);
  ATasks[0] := TTaskCreate(procedure() begin DB_ReadTable1; end);
  ATasks[1] := TTaskCreate(procedure() begin DB_ReadTable2; end);
  ATasks[2] := TTaskCreate(procedure() begin DB_ReadTable3; end);

  ATasks[0].Start;
  ATasks[1].Start;
  ATasks[2].Start; 

  TTask.WaitForAll(ATasks);
end;
Run Code Online (Sandbox Code Playgroud)

但是,假设我想更新主窗体以显示进度,即已读取哪个数据库表(或执行任何其他必要的主线程工作)。显然,我不能使用 Synchronise(),因为这会导致 WaitForall() 死锁,我不能使用 Queue(),因为它会在 WaitForAll() 完成后执行。

那么,有没有好的解决方案来解决这种“WaitForAll vs Synchronise”的情况?我想,这一定是很多人遇到的情况……需要等待全部完成,但又想更新主线程……

我想过这样的事情,用伪代码给出,替换 WaitForAll() 语句:

repeat 
  Applicaton.ProcessMessages; // or "ProcessSynchroniseMessages"
until "AllTaskCompleted"(ATasks);
Run Code Online (Sandbox Code Playgroud)

这行得通吗?有更好的解决方案吗?

我可以编写像 ProcessMessages 这样的自己的例程,但仅限于同步消息,即其他主窗体事件直到稍后才会执行吗?

提前谢谢了!

Rem*_*eau 5

TThread.Synchronize()并且TThread.Queue()不要使用窗口消息(好吧,有一条消息可以“唤醒”主线程以发出未决请求的信号,但实际的同步本身并不是基于消息的)。请求被放入一个全局队列,主线程在空闲时或检测到“唤醒”消息时检查该队列。您可以通过Classes.CheckSynchronize()直接调用该函数来手动泵送相同的队列:

while not TTask.WaitForAll(ATasks, 1000) do
begin
  // process any pending TThread.Synchronize() and TThread.Queue() requests
  CheckSynchronize(0);
  // process any pending UI paint requests, but not other messages
  Application.MainForm.Update;
  // anything else you need...
end;
Run Code Online (Sandbox Code Playgroud)