这是使用OmniThreadLibrary的正确方法 - 终止现有的,然后创建一个新的?

时间:2012-03-29 19:20:34

标签: delphi omnithreadlibrary

我使用优秀的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方法并且给定足够的时间来完成ThreadedParse时,我发现内存泄漏。关于什么可能导致内存泄漏的任何想法?谢谢!

编辑2 :阅读this blog post,我仍然无法确定问题可能是什么,因为Terminated中的每个步骤都会导致代码中断{{1}是真的......

编辑3 :回答Rob的问题:

  1. 在OnTerminated事件处理程序(此处未显示)中,FParserThread设置为“nil”,因此“FParser自行完成”,我的意思是if FParserThread <> nil then块未执行,其中case FParserThread因为它的解析已经完成而终止。

  2. 代码背后的逻辑是,这是一个代码编辑器,在任何代码编辑时,将会有一个线程被启动,将源代码解析为内部树表示,在新代码编辑的情况下发生了但是之前的解析thrad尚未编辑,程序将首先强制执行先前的解析线程然后启动一个新的解析线程。这可能不是一个好方法......

  3. 编辑4 :在阅读this similar SO question后,我将代码更改为调用FParserThread.Terminate而没有参数,这意味着,如果我理解正确,那么该语句只会发出信号线程结束,在实际线程任务内部,如果Terminated属性为True,我应用逻辑退出线程执行。

    现在有什么问题,在Tracetool的帮助下,我发现在调用FParserThread.Terminate之后OnTaskMessage事件(我清理记忆)将不再被解雇,这就是造成内存泄漏的原因....

2 个答案:

答案 0 :(得分:3)

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

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

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

如果线程没有在指定的时间限制内结束,那么你就会遇到更大的问题,强行杀死它将无法解决问题。

答案 1 :(得分:1)

OP在这里,使用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;