我使用优秀的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的问题:
在OnTerminated事件处理程序(此处未显示)中,FParserThread设置为“nil”,因此“FParser自行完成”,我的意思是if FParserThread <> nil then
块未执行,其中case FParserThread因为它的解析已经完成而终止。
代码背后的逻辑是,这是一个代码编辑器,在任何代码编辑时,将会有一个线程被启动,将源代码解析为内部树表示,在新代码编辑的情况下发生了但是之前的解析thrad尚未编辑,程序将首先强制执行先前的解析线程然后启动一个新的解析线程。这可能不是一个好方法......
编辑4 :在阅读this similar SO question后,我将代码更改为调用FParserThread.Terminate
而没有参数,这意味着,如果我理解正确,那么该语句只会发出信号线程结束,在实际线程任务内部,如果Terminated
属性为True
,我应用逻辑退出线程执行。
现在有什么问题,在Tracetool的帮助下,我发现在调用FParserThread.Terminate
之后OnTaskMessage
事件(我清理记忆)将不再被解雇,这就是造成内存泄漏的原因....
答案 0 :(得分:3)
您不必检查相关任务中的Terminated
属性。你正在调用Terminate(1)
,如果线程没有在你指定的1 ms窗口内结束,它将强制终止该线程。
然而,强行杀死一个线程真的不是一个好主意。当你杀死它时,该线程可能拥有互斥或临界区,因此杀死它会使共享数据处于不一致状态。这可能会对整个计划产生不利影响。
最好是通知你的线程你希望它终止,但给它一个更现实的终止截止日期。在另一个线程中,您应该偶尔检查线程是否已被要求终止,然后让它正常终止。
如果线程没有在指定的时间限制内结束,那么你就会遇到更大的问题,强行杀死它将无法解决问题。
答案 1 :(得分:1)
在调用者线程(通常是主线程)中,调用:
//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;