0

我有一个线程调用某种形式的函数来更新这个表单。任务完成后,线程使用结果更新表单,使用Synchronize并且在程序运行时一切正常。

当线程正在运行并且我关闭我遇到访问冲突的程序时,就会出现问题。它是由已经发布的线程更新表单引起的。在重新排列表单创建的顺序(调用Application->CreateForm)之后,它工作得很好,因为现在保存线程代码的表单是在更新表单之前创建的。似乎破坏顺序与创建顺序相反。

我还在表单析构函数中添加了一些代码,以确保如果表单在使用线程代码的表单之前被销毁,则线程终止。因此,在表单析构函数中重新排列表单创建顺序和/或代码可以解决问题。

但我有3个问题:

  1. 创建的形式被销毁的顺序是什么?它是否与我现在假设的创建顺序相反?

  2. 有没有更好的方法来完成上述任务 - 在线程完成处理数据后更新表单 GUI 项。现在我从线程本身使用Synchronize但有线程经验的人可能有更好的主意。我的另一个想法是什至删除CreateForm编译器生成的一堆并手动创建它们,只创建主表单CreateForm以更好地控制破坏顺序(如 Rob Kennedy 建议的那样 - http://pages.cs.wisc.edu/ 〜肯尼迪/创建形式)。

  3. 在典型应用程序中动态表单创建/销毁有多昂贵?使用表单隐藏并保存在内存中或关闭时销毁它更好吗?

4

1 回答 1

3

当您创建一个带有 的组件时OwnerOwner会将您的组件添加到它拥有的组件列表中。这发生在这段代码中:

procedure TComponent.Insert(AComponent: TComponent);
begin
  if FComponents = nil then FComponents := TList<TComponent>.Create;
  FComponents.Add(AComponent);
  if FSortedComponents <> nil then
    AddSortedComponent(AComponent);
  AComponent.FOwner := Self;
end;

如您所见,该组件已添加到列表的末尾。

当所有者被销毁时,它会调用DestroyComponents

procedure TComponent.DestroyComponents;
var
  Instance: TComponent;
begin
  FreeAndNil(FSortedComponents);
  while FComponents <> nil do
  begin
    Instance := FComponents.Last;
    if (csFreeNotification in Instance.FComponentState)
      or (FComponentState * [csDesigning, csInline] = [csDesigning, csInline]) then
      RemoveComponent(Instance)
    else
      Remove(Instance);
    Instance.Destroy;
  end;
end;

如您所见,循环首先处理最后一个成员。因此,组件以相反的顺序被销毁。

我个人不会依赖销毁命令。如果表单需要确保在销毁表单之前终止线程,我会在表单的析构函数中编写代码来强制执行。

使用Synchronize是解决许多问题的完美解决方案。我不可能说它是否是解决您问题的最佳方法,因为您还没有完全描述您的问题。

在典型应用程序中动态表单创建/销毁有多昂贵?

不是特别的。通常,表单是响应用户交互而显示的。程序创建表单的速度比用户处理表单的速度要快得多。所以动态创建表单很少成为问题。如果您想每秒创建和销毁数千个表单,这可能是个问题。但这会很奇怪。

于 2013-05-04T18:25:25.847 回答