1

我使用优秀的 OmniThreadLibrary 库来实现线程源代码解析,程序需要放弃现有的解析并在源代码更改时重新开始解析。

我使用下面显示的代码片段执行此操作,这是正确的方法吗?我还需要检查函数Terminated中线程的属性吗?ThreadedParseHtml

if FParserThread <> nil then
begin
  FParserThread.RemoveMonitor;
  FParserThread.Terminate(500);
end;

FParserThread := CreateTask(ThreadedParse);
FParserThread.SetParameter('SourceCode', Editor.Lines.Text);
FParserThread.MonitorWith(FParserThreadMonitor);
FParserThread.Run;

提前致谢!

编辑1:很抱歉重新打开这个问题,但我发现内存泄漏时FParserThread没有通过调用该Terminate方法并给定足够的时间自行完成......关于什么可能导致内存泄漏的任何想法?谢谢!

编辑2:阅读这篇博文,我仍然无法弄清楚问题可能是什么,因为在ThreadedParse代码中的每一步之后如果Terminated是真的......

编辑 3:回答 Rob 的问题:

  1. 在 OnTerminated 事件处理程序(此处未显示)中,FParserThread 设置为“nil”,因此“FParser 自行完成”是指该if FParserThread <> nil then块未执行,在这种情况下,FParserThread 被终止,因为它的解析已完成。

  2. 代码背后的逻辑是,这是一个代码编辑器,在任何代码编辑时都会启动一个线程来将源代码解析为内部树表示,以防发生新的代码编辑但之前的解析线程没有被编辑过,程序会先强制上一个解析线程再启动一个新的解析线程。这可能不是一个好方法......

编辑4:在阅读了这个类似的SO问题之后,我将代码更改为FParserThread.Terminate不带参数的调用,这意味着,如果我理解正确,该语句只会发出线程结束的信号,并且在实际线程任务中,我将逻辑应用于如果Terminated属性为,则退出线程执行True

现在的连线是,在Tracetool的帮助下,我发现在调用事件(我清理内存FParserThread.TerminateOnTaskMessage地方)后不会再次触发,这就是导致内存泄漏的原因......

4

2 回答 2

4

您不必检查Terminated相关任务中的属性。您正在调用Terminate(1),如果线程没有在您指定的 1 毫秒窗口内结束,它将强制终止线程。

但是,强行杀死一个线程确实不是一个好主意。当您杀死该线程时,该线程可能拥有互斥锁或临界区,因此杀死它会使共享数据处于不一致的状态。这可能会对您的整个程序产生不利影响。

更好的是通知您的线程您希望它终止,但给它一个更现实的终止期限。在另一个线程中,您应该偶尔检查线程是否已被要求终止,然后让它自己正常终止。

如果线程没有在指定的时限内结束,那么你就有更大的问题,强行杀死它并不能解决问题。

于 2012-03-29T20:22:29.327 回答
2

在这里,在使用 OmniThreadLibrary 超过 2 年之后,我的结论是停止 OTL 任务的正确方法是使用取消令牌。下面的代码示例。

在调用者线程(通常是主线程)中,调用:

//this will tell (not kill) the thread identified by myTask to stop.
myTask.CancellationToken.Signal;

在被调用线程中必须定期检查 task.CancellationToken.IsSignaled 属性,如果变为 true,则退出执行,线程终止将由系统和 OTL 处理:

if task.CancellationToken.IsSignaled then
  Exit;
于 2014-06-10T06:32:08.453 回答