multithreading - OmniThreadLibrary:如何检测所有递归调度(=池化)线程何时完成?

标签 multithreading delphi recursion threadpool omnithreadlibrary

假设我必须在后台递归地迭代存储在树结构中的项目,并且我想使用线程池中的多个线程(每个“文件夹”节点一个线程)来遍历这棵树。我已经成功地使用 OmniThreadLibrary 提供的几种不同的低级和高级方法来实现这一点。

但是,我还没有弄清楚如何正确检测扫描是否已实际完成,即每个最后一个叶节点都已被处理。

我在网上找到了各种例子,要么检查GlobalThreadPool.CountExecuting + GlobalThreadPool.CountQueued <= 0或者使用 IOmniTaskGroup.WaitForAll() 。不幸的是,这些方法似乎都不适合我。支票始终返回 True太早了,即仍有一些任务正在运行时。不过,我看过的所有示例都没有使用递归 - 以及那些没有使用线程池的示例 - 这可能从一开始就不是一个好的组合?

这是一个(非常)简化的示例代码片段,说明我目前正在尝试执行此操作:

procedure CreateScanFolderTask(const AFolder: IFolder);
begin
  CreateTask(ScanFolder)
    .SetParameter('Folder', AFolder)
    .Schedule();
end;

procedure ScanFolder(const ATask: IOmniTask);
var
  lFolder,
  lCurrentFolder: IFolder;
begin
  if ATaks.CancellationToken.IsSignalled then Exit;

  lCurrentFolder := ATask.Param['Folder'].AsInterface as IFolder;

  DoSomethingWithItemsInFolder(lCurrentFolder.Items);

  for lFolder in lCurrentFolder.Folders do
    begin
      if ATaks.CancellationToken.IsSignalled then Exit;
      CreateScanFolderTask(lFolder);
    end;
end;

begin
  GlobalOmniThreadPool.MaxExecuting := 8;
  CreateScanFolderTask(FRootFolder);

  // ??? wait for recursive scan to finish

  OutputResult();
end.

我尝试过的等待的一个示例实现是这样的(基于 example found on About.com ):

  while GlobalOmniThreadPool.CountExecuting + GlobalOmniThreadPool.CountQueued > 0 do
    Application.ProcessMessages;

但这似乎总是在“根线程”完成后立即退出。即使我使用 Sleep() 添加人为延迟- 调用它仍然总是退出得太早。似乎在执行任务列表中删除的一个任务与在该任务内计划添加到排队任务列表中的任务之间存在“间隙”...

实际上,我非常愿意使用事件处理程序,而不是等待扫描完成(另外,我不想使用 Application.ProcessMessages 因为我在无表单应用程序中也需要它)并且我已经尝试过 IOmniTaskControl.OnTerminated并使用 TOmniEventMonitor但当这些任务为每一项已完成的任务触发时,我仍然需要检查当前任务是否是最后一项,这又归结为与上面相同的问题。

或者是否有更好的方法来创建可以避免此问题的任务?

最佳答案

一个简单的方法是自己统计“要处理的文件夹”。每增加一个值 当您创建文件夹任务并在每次处理文件夹时递减它时。

var
  counter: TOmniCounter;

counter.Value := 0;

procedure ScanFolder(const ATask: IOmniTask);
var
  lFolder,
  lCurrentFolder: IFolder;
begin
  if ATaks.CancellationToken.IsSignalled then Exit;

  lCurrentFolder := ATask.Param['Folder'].AsInterface as IFolder;

  DoSomethingWithItemsInFolder(lCurrentFolder.Items);

  for lFolder in lCurrentFolder.Folders do
    begin
      if ATaks.CancellationToken.IsSignalled then Exit;
      counter.Increment;
      CreateScanFolderTask(lFolder);
    end;
  counter.Decrement;
end;

关于multithreading - OmniThreadLibrary:如何检测所有递归调度(=池化)线程何时完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11137969/

相关文章:

java - 多线程程序的处理器数量

Delphi XE3 Ctrl+Z 也撤消插入符号移动

database - sql with-recursive 语句如何解释?

c++ - 如果另一个线程将元素推送到 vector 的末尾, vector 上的迭代器会失效吗?

创建用户级线程

delphi - 如何将特定节点移动到第一个索引?

c - 我的二进制搜索功能无法正常工作

java - 在一台机器上出现堆栈溢出错误,但在同一代码上另一台机器却没有

python - 线程中的for循环在Python 3中运行一次

JavaScript 日期转 Delphi TDateTime