什么是TExternalThread?终止基于线程的计时器时“无法终止外部创建的线程”

时间:2010-02-08 13:05:36

标签: delphi multithreading delphi-2010 external

在关闭我的应用程序时,这种情况发生了一半,我在设计时在表单上放置了TLMDHiTimer,Enabled设置为true。 在我的OnFormClose事件中,我调用MyLMDHiTimer.Enabled:= false。当这个被调用时,我有时(大约一半的时间)得到这个例外。

我调试并进入调用,发现它是LMDTimer.pas中的第246行,它会出现此错误。

FThread.Terminate;

我使用的是最新版本的LMDTools。我在周末之前完成了LMD工具的重新安装,并且已经将组件移除并重新添加到表单中。

根据我的发现,这与TExternalThread有关,但Embarcadero没有关于它的文档,我没有在LMDTools源代码中找到任何引用它的文档。

使用完全更新的RAD Studio 2010,Delphi 2010。

真正让我感到不安的是,没有任何文件记录。谷歌实际上正在谈论它的结果一个结果,其中有人说这个错误是由试图终止TExternalThread引起的。 但是看看这个LMDHiTimer的源代码,不是一次它的目的是做任何事情,而是创建一个常规的TThread。 我可以找到的一个google结果,Embarcadero上的Thread: Cannot terminate an externally created thread? 提到使用GetCurrentThread()和GetCurrentThreadId()来获取挂钩到现有线程所需的数据,但TLMDHiTimer没有这样做。它只是创建自己的TThread后代,它有自己的Create()构造函数(当然是重写,并且在构造函数的开头继承了调用)

那么......这个TExternalThread到底是什么?还有其他人遇到过这种例外吗?也许找出了解决方案或解决方法? 我已经向LMDTools自己的支持提出了几乎完全相同的问题,但在多个地方提问都不会有什么坏处。

提前感谢你的帮助。

4 个答案:

答案 0 :(得分:11)

TExternalThread包装了一个Delphi RTL没有创建的线程。它可能代表属于OS线程池的线程,或者可能是程序中另一个DLL创建的线程。由于线程正在执行不属于关联的TExternalThread类的代码,因此Terminate方法无法通知线程您希望它停止。

Delphi TThread对象将其Terminated属性设置为True,并且被覆盖的Execute方法将被定期检查该属性,但由于此线程是非Delphi代码,因此没有Execute方法,并且任何Terminated属性只有之后才出现线程代码已经写在其他地方(而不是通过覆盖Execute)。

新闻组主题提示你的案件可能会发生什么:

  

...你的内存已损坏导致TThread.FExternalThread成员变为非零值。

可能是由于组件库中的错误,或者可能是由于您自己的代码中存在错误。您可以使用调试器的数据断点来尝试查找。在计时器的线程构造函数中设置断点。当程序暂停时,使用“运行”菜单上的“添加断点”命令,使用新对象的FExternalThread字段的地址添加数据断点。此后,如果该字段的值发生变化,调试器将暂停并显示更改后的内容。 (每次运行程序时,数据断点都会重置,因为IDE假定每次都不会在同一地址分配对象。)

答案 1 :(得分:5)

代码是否有可能试图终止已经被破坏的TThread?如果你设置了FreeOnTerminate,这很容易发生。

我在主窗体上放置的组件的构造函数中诊断出类似(相反?)错误,“无法在正在运行或挂起的线程上调用Start”时注意到了您的帖子。当我删除Start()时,该错误被更多告知错误所取代,例如“无效指针操作”和“访问冲突”,在相应的析构函数中。该组件试图在TThread被释放后操纵其TThread对象,从而使事情符合墨菲定律。当我修复它时,我能够在没有返回“无法调用启动”错误的情况下替换Start()调用。

通过类比,你的问题可能是你的FExternalThread的地址在析构函数/终止调用之前被回收并破坏了吗?在我们的例子中,我们有一个Singleton Instance Pattern的错误实现;但同样,FreeOnTerminate似乎也是一个可能的嫌疑人。

[仅供参考:我正在使用我在RAD Studio XE下使用C ++]

答案 2 :(得分:0)

问题是,当您创建FExternalThread实例时,TThread默认情况下未初始化为false。因此,您无法保证此变量中的值(有时可能是真的,有时是假的)。

答案 3 :(得分:-1)

同样的问题让我疯了好几个月。我详细检查了我的线程代码,直到我几乎失明。

最后我买了一个很好的例外系统(EurekaLog),它直接把我带到导致问题的第三方组件。这个组件TAbLED有一个属性,可以通过某种时序线程将其设置为flash。将其设置为不闪存解决了问题。