TExternalThread TThread -- Delphi -- Cannot terminate an externally created thread ?
Cannot terminate an externally created thread ?
The VCL has a new TExternalThread class which derives from TThread
and can be attached to an existing Win32 thread object by filling in
the Handle and ThreadID properties using the GetCurrentThread() and GetCurrentThreadId()
Win32 API functions instead of creating a new thread object by calling the Win32 API CreateThread() function.
The error you are seeing can only occur
if you are calling Terminate() on a TExternalThread instance.
This is correct, the exception is raised from a Terminate() call.
How shoud TExternalThreads be terminated?
A regular TThread object that you create yourself is not a TExternalThread instance.
The error message you are seeing cannot be raised by your own custom threads,
unless you have corrupted memory that causes the TThread.FExternalThread member to become a non-zero value.
The only thing in the VCL that creates TExternalThread instances is the TThread.GetCurrentThread() method.
You can't terminate a TExternalThread object, by design, because it represents a thread that TExternalThread does not own.
The *only* way you can get that error is if you call Terminate() on a TThread object
whose ExternalThread property is true,
such as a TThread object that was obtained from the TThread.GetCurrentThread() method.
But another possibility would be if random memory got corrupted
and the TThread.FExternalThread member was an unsuspecting victim of that corruption.
Is that possible, that XE4 creates TExternalThread by default ?
No.
The *only* way TExternalThread is created is if the TThread.GetCurrentThread() method is called.
What is TExternalThread?
“Cannot terminate externally created thread” when terminating a thread-based timer
This happens half of the time when closing my application in
which I have placed a TLMDHiTimer on my form in design time, Enabled set to true.
In my OnFormClose event, I call MyLMDHiTimer.Enabled := false.
When this is called, I sometimes (about half of the time) get this exception.
I debugged and stepped into the call and found that it is line 246 in LMDTimer.pas that gives this error.
FThread.Terminate;
I am using the latest version of LMDTools.
I did a complete reinstall of LMD tools before the weekend and
have removed and re-added the component to the form properly as well.
From what I've found, this has something to do with TExternalThread,
but there's no documentation on it from Embarcadero and
I haven't found anything referencing it within the LMDTools source code.
Using fully updated RAD Studio 2010, Delphi 2010.
What really upsets me here is that there's no documentation whatsoever.
Google yeilds one result that actually talks about it, in which someone says that the error
is caused by trying to terminate a TExternalThread.
But looking at the source-code for this LMDHiTimer, not once does it aim to do anything but create a regular TThread.
The one google result I could find,
Thread: Cannot terminate an externally created thread?
on Embarcadero mentions using GetCurrentThread() and GetCurrentThreadId() to get the data necessary
to hook on to an existing thread, but the TLMDHiTimer does no such thing.
It just creates its own TThread descendant with its own Create() constructor
(overridden of course, and calls inherited at the start of the constructor)
So... What the heck is this TExternalThread?
Has anyone else run into this kind of exception?
And perhaps figured out a solution or workaround?
I've asked almost the exact same question to LMDTools' own support,
but it can't hurt to ask in multiple places.
Thank you in advance for any assistance.
TExternalThread wraps a thread that the Delphi RTL didn't create.
It might represent a thread belonging to the OS thread pool,
or maybe a thread created by another DLL in your program.
Since the thread is executing code that doesn't belong to the associated TExternalThread class,
the Terminate method has no way to notify the thread that you want it to stop.
A Delphi TThread object would set its Terminated property to True,
and the Execute method that got overridden would be expected to check that property periodically,
but since this thread is non-Delphi code, there is no Execute method,
and any Terminated property only came into existence after the thread code was already
written someplace else (not by overriding Execute).
The newsgroup thread suggests what's probably happening in your case:
... you have corrupted memory that causes the TThread.FExternalThread member to become a non-zero value.
It might be due to a bug in the component library, or it could be due to a bug in your own code.
You can use the debugger's data breakpoints to try to find out.
Set a breakpoint in the timer's thread's constructor.
When your program pauses there, use the "Add Breakpoint" command
on the Run menu to add a data breakpoint using the address of the new object's FExternalThread field.
Thereafter, if that field's value changes, the debugger will pause and show you what changed it.
(The data breakpoint will get reset each time you run the program
because the IDE assumes the object won't get allocated at the same address each time.)
I did as you said, but the only time this breakpoint is triggered is
upon the destruction of the component at the closing of the application.
I hit Shift+F7 to trace to the next step in the source code
(using debug dcus, so I get to see all the underlying delphi classes too)
and the call stack looks as follows: pastebin.org/88904
That looks to me like it's just doing the regular destruction of form components.
The call stack you show is not the destruction of the timer component.
It looks like it's the destruction of some form.
Was the FExternalThread field still False?
What new value did that memory contain when the data breakpoint triggered?
Yes, it looks to be the destruction of my application's main form.
The Timer component is placed on it, which makes me interpret the call stack
as the component being destroyed during the form's destruction
(the form should destroy all components on it during destruction, right?)
It seems that when I evaluate the value of the address of FExternalThread,
it always comes up as true, even when the delphi debugger itself says that it is false.
I write down @FExternalThread and do Boolean($Addess) in evaluation
and get 'true' even during creation when just FExternalThread returns 'false'. –
Actually, no, nevermind.
I managed to propertly retrieve the value at the time the data breakpoint is triggered
using PBoolean($address)^ and it is indeed set to true.
Edit: Nope, happens on other computers too so it's supposedly something in this app I guess?
Still, it's weird that the data breakpoint only triggers during destruction and
the data is at that time already altered.
So my value has been changed without my application changing it?
I'm gonna have to try running this app on another computer to see if the same error happens there too
Aaaaaaaaand I ran it on a different computer, no difference.
I just stepped through my code down to the very last line of my application's .dproj
and found that the value at the address of FExternalThread during the creation of the thread is false the entire time
Is there any chance the code might be trying to Terminate an already Destroyed TThread?
This could easily happen if you have FreeOnTerminate set.
I noticed your post while diagnosing a similar (opposite?) error,
"Cannot call Start on a running or suspended thread"
in the constructor of a component placed on the main form.
When I removed the Start(), that error was replaced by more telling errors,
e.g. "invalid pointer operation" and "access violation",
in the corresponding destructor.
The component was trying to manipulate its TThread object after the TThread was Freed,
thus leaving things up to Murphy's law.
When I fixed that, I was able to replace the Start() call without the "Cannot call Start" error returning.
By analogy, could your problem be that the address of your FExternalThread had been recycled
and clobbered before the destructor/Terminate call?
In our case, we had a buggy implementation of the Singleton Instance Pattern;
but again, FreeOnTerminate also seems like a likely suspect.
[FYI: I'm using I'm using C++ under RAD Studio XE]
This same problem drove me nuts for several months.
I went over my thread code in detail until I nearly went blind.
Finally I bought a good exception system (EurekaLog) and
it drove me directly to a third party component that was causing the problem.
This component, TAbLED, has a property to set it to flash with some sort of timing thread.
Setting it to not flash solved the problem.
Problem is that FExternalThread isn't initialized to false by default
when you're creating TThread instance.
So you can't guarantee what value be in this variable
(sometimes there can be true, sometimes false).
Yes, the FExternalThread member is initialized when a TThread object is created.
Being a TObject descendant, all of the TThread members are zero-initialized upon allocation
before the TThread constructor is then called.
That means FExternalThread is implicitally initialized to False.
The only way FExternalThreadcan be set to true is
if either an actual TExternalThread object is created (such as by the TThread.GetCurrentThread() class method),
or if memory is being corrupted by the app's code.
TExternalThread TThread -- Delphi -- Cannot terminate an externally created thread ?的更多相关文章
- Correct thread terminate and destroy
http://www.techques.com/question/1-3788743/Correct-thread-destroy Hello At my form I create TFrame a ...
- TThread 线程的例子
TThread 线程的例子 D:\Documents\Embarcadero\Studio\14.0\Samples\CPP\RTL\Threads TThread类 该线程类可以完成大多数的线程 ...
- Delphi thread exception mechanism
http://www.techques.com/question/1-3627743/Delphi-thread-exception-mechanism i have a dilema on how ...
- Delphi 200X、XE中如何用并行实现循环的计算
interface uses Classes, SysUtils; type TParallelProc = reference to procedure(i: Integer; ThreadID: ...
- Four Ways to Create a Thread
Blaise Pascal Magazine Rerun #5: Four Ways to Create a Thread This article was originally written ...
- Programming for thread in Java
Programming for thread in Java Override Annotation package java.lang; import java.lang.annotation.El ...
- 多线程爬坑之路-Thread和Runable源码解析
多线程:(百度百科借一波定义) 多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提 ...
- java多线程系类:JUC线程池:03之线程池原理(二)(转)
概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
随机推荐
- Unicode和汉字编码小知识
Unicode和汉字编码小知识 将汉字进行UNICODE编码,如:“王”编码后就成了“\王”,UNICODE字符以\u开始,后面有4个数字或者字母,所有字符都是16进制的数字,每两位表示的256以内的 ...
- C++ STL知识点小结
1.capacity(容量)与size(长度)的区别. size(长度)指容器当前拥有的元素个数. capacity(容量)指容器在必须分配新存储空间之前可以存储的元素总数.
- 浏览器的DNS缓存
通过设置hosts文件可以强制指定域名对应的IP,当修改hosts文件,想要浏览器生效,最直接的方法关闭浏览器后重新开启:如果不想重启浏览器,只需要清空浏览器的DNS缓存即可.清空DNS缓存在chro ...
- Linux基本命令(8)网络操作的命令
网络操作命令 命令 功能 命令 功能 ftp 传送文件 telnet 远端登陆 bye 结束连线并结束程序 rlogin 远端登入 ping 检测主机 netstat 显示网络状态 8.1 ftp命令 ...
- PDF数据提取------3.解析Demo
1.PDF中文本字符串格式中关键值信息抓取(已完成) 简介:这种解析比较传统最简单主要熟练使用Regular Expression做语义识别和验证.例如抓取下面红色圈内关键信息 string mett ...
- JDT入门
1.打开Java类型 要打开一个Java类或Java接口以进行编辑,可以执行以下操作之一: 在编辑器中所显示的源代码里选择所要编辑的Java类或Java接口的名字(或者简单地将插入光标定位到所要编辑的 ...
- 【WPF】ContentControl Style定义与使用出现问题后 -- 引发的思考
一.背景 使用WPF的朋友,大家都很喜欢采用定义控件的公共样式,以便整个框架对该资源的使用,好处就是可以达到代码复用.系统风格统一等: 1. 定义资源 <Style TargetT ...
- Strassen算法
如题,该算法是来自德国的牛逼的数学家strassen搞出来的,因为把n*n矩阵之间的乘法复杂度降低到n^(lg7)(lg的底是2),一开始想当然地认为朴素的做法是n^3,哪里还能有复杂度更低的做法,但 ...
- c++面试题总结(2)
1. C中static有什么作用 (1)隐藏. 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,故使用static在不同的文件中定义同名函数和同名变量,而不必担心命 ...
- TcxDBTreeList导出EXCEL
function ExportExcel(tree: TcxDBTreeList; const fileName: string = '1.xls'): Boolean;var sd: TSave ...