如何确定主线程无法响应Omni线程库的原因?

时间:2013-01-10 02:59:11

标签: delphi freeze omnithreadlibrary otl

平台:Delphi与VirtualTreeView SVN 5.1.0& OmniThreadLibrary 3 SVN&德尔福XE2

最初我认为问题是VirtualTreeView。我需要每隔1秒或更短时间将节点添加到VST。但似乎很快或更晚的CPU速率将达到50%或更高,因为整个应用程序完全没有响应。

  var FAbort:Boolean;
  .....

  procedure TrmMain.btnAddNodeClick(Sender: TObject);
    begin
      while not FAbort do
      begin
        VstMain.RootNodeCount:= VstMain.RootNodeCount + 1;
        Sleep(10);
        Application.ProcessMessages;
      end;
    end;

任何人都可以提供帮助? TIA!

编辑:似乎问题来自 OTL 。使用上面的代码时,最小化CPU的应用程序不到1%,甚至将10ms睡眠改为1ms。

但是,下面的代码将重现让我烦恼的问题。

procedure TForm1.btn5Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to 1 do
    CreateTask(
      procedure(const Task: IOmniTask)
      begin
        while not FAbort do
        begin
          Task.Comm.Send(1, 0);
          Sleep(10);
        end;
      end).OnMessage(
      procedure(const Task: IOmniTaskControl; const Msg: TOmniMessage)
      begin
        vst1.AddChild(nil);
      end).Run;
end;

PS:为了避免泛滥到OTL默认的1000队列大小,我在每个线程中都有一个锁定,等待在下一个Task.Comm.Send操作之前完成添加节点。

PPS:这里的10ms只是为了快速重现问题,而不是在实际情况下。所以不要问为什么?

好的,结论是:如果你需要定期更新这个节点,就不要在单个节点上添加太多节点,节点越多,更新它们的CPU时间就越多。

2 个答案:

答案 0 :(得分:2)

在我看来,当基础模型发生变化时,不应同步更新视图,尤其是不是每次都更新。

VirtualTreeView是一个可视化控件。人类不需要实时查看树更新,每秒浪费超过3倍。所以不要这样做。

相反,更新模型(对象,类),设置通知标志,然后(从TTimer),执行VirtualStringTree.RootNodeCount的异步SINGLE更新,最多每秒3次。 (每个333毫秒的这个更新标志的多个设置导致最小等待时间为333毫秒,直到它实际更新为止。)这是我的任意用户界面“比这更快,它只是闪烁和流失,并且没有任何用处”常数

Delphi自己的开发人员使用VirtualTreeView遇到了这个问题,我知道因为我记录了涉及的QC错误。如果您在Delphi 2009中执行了足够的“OutputDebugString”消息,IDE将变得无响应。为什么?因为他们做了你正在做的事情。不要这样做。我并不是说用户点击会导致屏幕刷新前等待333毫秒。我说一些连续生成树内容的进程应该只通知树的“视图控制器”每秒更改3次,最大值。

答案 1 :(得分:1)

如果使用AddChild()函数添加节点,则可能比访问RootNodeCount属性更好。

例如:

procedure TMyForm.OnTimer( Sender: TObject );
var
  Node: PVirtualNode;
begin
  Node := MyTree.AddChild( nil );
  // fill in details with GetNodeData( Node );

end;

更好的是:使用计时器并尝试每个时间间隔添加一些项目:

procedure TMyForm.OnTimer( Sender: TObject );
begin
  AddToList( ... );
end;

procedure TMyForm.OnTimer( Sender: TObject );
var
  Node: PVirtualNode;
  Item: <Some iterator>;
begin
  MyTree.BeginUpdate();
  try
    for Item in <somelist> do begin
      Node := MyTree.AddChild( nil );
      // fill in details with GetNodeData( Node );
    end;
  finally
    MyTree.EndUpdate();
  end; 
end;