微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

预计未释放Omnithread未观察到的嵌套线程

如何解决预计未释放Omnithread未观察到的嵌套线程

背景

我的旗舰应用似乎泄漏了内存。好吧,不是真的,而是在运行时。调查表明,当应用关闭时,内存“泄漏”已解决,但在关闭之间没有解决

我正在使用后台线程,即iself启动了另一个线程。这两个线程(父线程和子线程)都是“未观察到”的,这将导致在踩踏完成后释放并释放TOmniTaskControl对象。

实验代码

procedure TfrmMain.MyTestProc(const aTask: IOmniTask);
begin
  sleep(100);
  SGOutputDebugStringFmt('%s.MyTestProc for %s',[ClassName,aTask.Name]);
  sleep(100);
end;

procedure TfrmMain.MynestedTestProc(const aTask: IOmniTask);
var lTask:IOmniTaskControl;
begin
  sleep(100);
  SGOutputDebugStringFmt('%s.MyTestProc for %s',aTask.Name]);
  lTask:=CreateTask(MyTestProc,'nestedTask');
  lTask.Unobserved.Run;
  sleep(100);
end;

procedure TfrmMain.btSimpleThreadClick(Sender: TObject);
var lTask:IOmniTaskControl;
begin
  lTask:=CreateTask(MyTestProc,'SimpleThread');
  lTask.Unobserved.Run;
end;

procedure TfrmMain.btnestedThreadClick(Sender: TObject);
var lTask:IOmniTaskControl;
begin
  lTask:=CreateTask(MynestedTestProc,'nestedThread');
  lTask.Unobserved.Run;
end;

调试时,在TOmniTaskControl.Destroy上设置断点,并在手表TOmniTaskControl.Name上看到以下内容

  • btSimpleThreadCLick:
    1. 要创建用于'SimpleThread'的TOmniTaskControl
    2. “ SimpleThread”的TOmniTaskControl被破坏
  • btnestedThreadCLick:
    1. 已创建“ nestedThread”的TOmniTaskControl
    2. 已创建“ nestedTask”的TOmniTaskControl
    3. nestedThread”的TOmniTaskControl被销毁

问题:“ nestedTask”的TOmniTaskControl未被销毁。另一个问题是,也没有调用OnTerminate。 然后,在关闭应用程序时,“ SimpleThread”的TOmniTaskCOntrol被销毁。 (而且,OnTherminate被解雇了)

解决方法

我想出了解决方案,似乎可以解决问题。然而,问题是,我通常不从手头就有TOmniEventMonitor的形式运行子线程。因此,我必须为此创建一个 global TOmniEventMonitor对象。 但这不是UnObserved方法的全部要点吗?

procedure TfrmMain.MynestedTestProc(const aTask: IOmniTask);
var lTask:IOmniTaskControl;
begin
  sleep(100);
  SGOutputDebugStringFmt('%s.MyTestProc for %s','nestedTask');
  lTask.MonitorWith(OmniEventMonitor).Run; // OmniEventMonitor is a component on my form
  sleep(100);
end;

嗯,中学工作...有点。它不允许无人看管地释放我的线程。 如果将nestedTestProc更改为下面的代码,则nestedTaskgets将在预期的时刻被销毁。不幸的是,这种解决方案显然不是“不可观察”的

procedure TfrmMain.MynestedTestProc(const aTask: IOmniTask);
var lTask:IOmniTaskControl;
begin
  sleep(100);
  SGOutputDebugStringFmt('%s.MyTestProc for %s','nestedTask');
  try
    lTask.Run;
    lTask.WaitFor(2000);
  finally
    lTask:=nil;
  end;
  sleep(100);
end;

更新20201029 >>

完成主任务并且其关联的Monitor已被销毁时,通常会发生无效句柄(1400)错误。 因此,万一有一个“拥有的”监视器正在监视其他线程,“主”任务线程就不会死。

因此要进行检查,我更改了时间(使用sleep())以确保子任务在主任务完成之前 完成。 现在,无效句柄错误消失了,并且成功发布了COmniTaskMsg_Terminated消息。 但是仍然不处理子任务的ComniTaskMsg_Terminated。 (我希望MasterTask的线程可以处理此问题。) IMO有2个问题:

  1. 无法观察的显示器的寿命管理
  2. 关闭未监视的监视器的管理,该管理应保持“拥有”线程处于活动状态并继续处理消息,直到所有 监视的线程/任务消失了。

我还想知道这些关闭消息是否应该由应用程序主线程(似乎现在是这种情况)处理/处理,还是通过检查GTaskControlEventMonitorPool中所有监视器的单独线程来处理/处理。友邦保险,相当复杂的东西:s ...

考虑到这一点,应由应用程序主线程(因此Monitor.ThreadID=MainThreadID)创建的监视器应在主线程消息循环中处理其消息,而其他所有监视器可能都需要由单独的线程处理。 ..太令人困惑了!我将看看是否为此编写了单元测试,以证明我期望发生的事情。

问题

使用OmniThreadLibrary,如何在线程内部使用未观察的线程,并避免所描述的内存泄漏?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。