JackT 1 Posted Saturday at 09:19 AM Has anyone come across an issue where by you create a thread using TThread then end it by calling Terminate on it, and then recreate the thread again, then terminate the 2nd instance of the thread using the terminate only to find that the 2nd instance on termination gets stuck in an infinite loop after it exits the Execute block. The program appears to be stuck in ntdll.dll and the whole program has hung not just the terminating thread. So to be clear all the code in the Execute block has finished executing. I am a bit stuck - sometimes I can manage to create and destroy the thread 3 times. I think this old post might describe the issue I am having. I Know it's on the FPC forum but it specifically mentions Delphi in the post. https://gitlab.com/freepascal.org/fpc/documentation/-/issues/34530 Share this post Link to post
DelphiUdIT 267 Posted Saturday at 09:54 AM 25 minutes ago, JackT said: Has anyone come across an issue where by you create a thread using TThread then end it by calling Terminate on it, and then recreate the thread again, then terminate the 2nd instance of the thread using the terminate only to find that the 2nd instance on termination gets stuck in an infinite loop after it exits the Execute block. The program appears to be stuck in ntdll.dll and the whole program has hung not just the terminating thread. So to be clear all the code in the Execute block has finished executing. I am a bit stuck - sometimes I can manage to create and destroy the thread 3 times. I think this old post might describe the issue I am having. I Know it's on the FPC forum but it specifically mentions Delphi in the post. https://gitlab.com/freepascal.org/fpc/documentation/-/issues/34530 Never had such issues. I use a lot of TThreads (form 5 to 50), all manually created and destroyed in my applications. But "FreeOnTerminate" is always set to FALSE. Never used it with True sets, except in anonymous threads. And I don't create and destroy most threads continuously, but leave them in a WaitFor state, until I use them again. I'll try to do some tests in one my application left them to "autofree" .... Share this post Link to post
Dalija Prasnikar 1570 Posted Saturday at 09:58 AM 37 minutes ago, JackT said: Has anyone come across an issue where by you create a thread using TThread then end it by calling Terminate on it, and then recreate the thread again, then terminate the 2nd instance of the thread using the terminate only to find that the 2nd instance on termination gets stuck in an infinite loop after it exits the Execute block. It would help if you can post the code example here. With threads even slight change in code can make a difference. But the example in the link shows waiting for self destroying thread and this is something which cannot be done with such thread. Hanging is expected behavior. 1 Share this post Link to post
Olli73 8 Posted Saturday at 09:59 AM Do not use "FreeOnTerminate" and free it in your code after your "waitfor". Alternatively do not use "WaitFor", use the event "OnTerminate" of the thread to proceed your work. This event is called from MainThraed Share this post Link to post
JackT 1 Posted Saturday at 10:44 AM The actual call that hangs in TThread is EndThread which calls the windows function ExitThread. I think ExitThread hangs if there are still open handles to the Thread. To close a handle to a thread code must use the windows CloseHandle function. It would be handy to get a count of open handles to the thread before ExitThread is called, and a list of objects with open handles. In that way I could discover which object has on open handle. It's just a bit weird I can exit the first instance of my threaded class, but subsequent instances hang the program on exit from Execute. I think reusing the same thread and suspending it would be a great work around for what I am trying to do. There is no real need to destroy it and recreate it constantly. The code inside Execute method is very complex which is why I haven't posted it. Share this post Link to post
Dalija Prasnikar 1570 Posted Saturday at 01:34 PM You don't need to post the code within Execute. We just need to know how are you creating and waiting for a thread. Is it a self destroying thread, or not. If it is self destroying thread with FreeOnTerminate set to True, then you cannot wait for it. If you need a waitable thread, just use a thread with manual memory management and free it when you are done. There is nothing wrong with creating and destroying thread when you need one. The only problem with recreation is that creating and starting a thread takes some small amount of time, and if you need to do that frequently (multiple times in a second) then such code will have some small impact on performance. Share this post Link to post
DelphiUdIT 267 Posted Saturday at 04:21 PM For my tasks, "FreeOnTerminate" is always set to False in all my applications. There are a lot of reasons for that (I repeat, for my uses), one of them is that I need a waitable thread 99% of the times. If your thread release a resources, then you must use the "waitfor" or similar since the thread can be busy before free it or resuse it (and this is the real reason why I cannot use FreeOnTerminate). And even if there's no need to release resources, there's no way to know when a thread with FreeOnTerminate set to True will actually terminate. By running tests under load and in a 64-bit Windows environment (my applications generate an average load of around 75% on 32-thread Intel i9 processors), I found that low-priority threads take a long time to release. In some cases, it can take up to a few tens of milliseconds, so without a WaitFor, it's a risk. Share this post Link to post
Remy Lebeau 1674 Posted Saturday at 08:05 PM (edited) 3 hours ago, DelphiUdIT said: And even if there's no need to release resources, there's no way to know when a thread with FreeOnTerminate set to True will actually terminate. Yes, there is - use the TThread.OnTerminate event to signal your waiting code, such as via a TEvent object. Just know that the event handler is called in the main thread, so if that will cause a sync issue, you can always override the TThread.DoTerminate() method to call the OnTerminate handler directly (or do anything else) without syncing it, as DoTerminate() is called in the worker thread and calls the OnTerminate handle via TThread.Synchronize() by default. Edited Saturday at 08:06 PM by Remy Lebeau 1 Share this post Link to post
Kas Ob. 160 Posted Sunday at 06:31 AM 20 hours ago, Olli73 said: Do not use "FreeOnTerminate" and free it in your code after your "waitfor". 16 hours ago, Dalija Prasnikar said: If it is self destroying thread with FreeOnTerminate set to True, then you cannot wait for it. Great, correct and make sense, but the documentation should say so, also that is bad design in the first place, and i don't want to go there, but have to say you don't design such always loaded foot gun and remove the safety. Someone should open a ticket and request to make WaitFor raise an exception in case the FreeOnTerminate is true, doesn't that make more sense ? Share this post Link to post
Dalija Prasnikar 1570 Posted Sunday at 09:55 AM (edited) 3 hours ago, Kas Ob. said: Great, correct and make sense, but the documentation should say so, also that is bad design in the first place, and i don't want to go there, but have to say you don't design such always loaded foot gun and remove the safety. I guess it was not anticipated that developers would store references to self destroying threads. And without having a reference you cannot wait for such thread. References to self destroying threads basically become invalid the moment the thread is started and they can only be used for initial configuration for threads that were created in suspended state. Once thread starts running, you should not touch the reference anymore. From documentation: https://docwiki.embarcadero.com/Libraries/Athens/en/System.Classes.TThread.CreateAnonymousThread Quote The thread is also marked as FreeOnTerminate, so you should not touch the returned instance after calling Start. It is possible that the instance had run and then has been freed before other external calls or operations on the instance were attempted. https://docwiki.embarcadero.com/Libraries/Athens/en/System.Classes.TThread.FreeOnTerminate Quote Warning: When FreeOnTerminate is true, the Execute method may run and then free the thread before your application can execute the next line of code. Thus, you should not call any methods of the thread object when FreeOnTerminate is true unless you create the thread in a suspended state. FreeOnTerminate is best left for threads that simply perform a task and then naturally terminate. If you want to communicate with the thread or otherwise interact with it, including telling it when to terminate, FreeOnTerminate should never be used. I am not going to discuss about how one can potentially use anonymous threads beyond their intended purpose: being fire and forget kind of thread, because such code can be very fragile and cause more problems than it solves. And like I mentioned earlier in this thread, without having a very specific code and a use case, it can be hard to discuss potential problems and solutions because in multithreading even slight changes in code and how it is used can make a huge difference and break it. Edited Sunday at 10:00 AM by Dalija Prasnikar 1 Share this post Link to post
Kas Ob. 160 Posted Sunday at 11:28 AM 1 hour ago, Dalija Prasnikar said: The thread is also marked as FreeOnTerminate, so you should not touch the returned instance after calling Start. So what is/was the point from design point to return TThread ? (shouldn't be different creature with single method "Start") I know the details, i pointing the failure to protect the developer by design and depending on well you have been warned (somewhere). IMHO, once FreeOnTerminate is true then most methods should raise exception to make sure it will work always as expected, not sometimes, and here i am pointing to the fact FreeOnTerminate was runtime adjustable at anytime, while it should fixed since the creating that TThread, again it is my opinion. Share this post Link to post
Dalija Prasnikar 1570 Posted Sunday at 06:28 PM 6 hours ago, Kas Ob. said: So what is/was the point from design point to return TThread ? (shouldn't be different creature with single method "Start") Because TThread can be self destroying or not based on the value in FreeOnTerminate property which can be configured after construction. Besides that property, there are others that can be configured before thread starts running, Also how would you prevent developers from taking reference of any abstract class that is meant to be extended and is therefore publicly accessible? Share this post Link to post
Kas Ob. 160 Posted Monday at 06:41 AM 11 hours ago, Dalija Prasnikar said: Also how would you prevent developers from taking reference of any abstract class that is meant to be extended and is therefore publicly accessible? By not returning TThread in the first place, and using smaller creature (TAnonThread, TThreadWorker, TThreadedRoutine....) with only can-be-used properties (with getter/setter) before start, now let see what one can use before start,... hmmm... nothing !, except priority and name and a maximum of three events OnBeforeExecute, OnDoneExecute and OnTerminate, everything else is useless and dangerous from this point after the method "Start" CreateAnonymousThread is mute and return a class that can not be extended, so fundamentally is wrong to return a class that has dangerous publics, it should return a class that can't be abused, right ? (by the way i don't use anonymous thread and hate them more than anything, their exceptions are anonymous and their call stack is unreadable and different platform like ARM their exceptions are fatal and time wasting), Now back to FreeOnTerminate, the danger of using FreeOnTerminate is coming from it allowed to be used and might work, but really put the undefined behavior in hidden state that might fail in the future or with different parameters like parsing smaller files than expected or under different OS state, what i am saying is that if WaitFor worked most the time but hid that dangerous behavior then the the design should be fixed, and it should raised exception with FreeOnTerminate is True on lets say WaitFor, this will prevent the working state (the dangerous state) from stay hidden and force the developer to rethink their design, so no more it it is working fine then it will work forever fine. Share this post Link to post
Dalija Prasnikar 1570 Posted yesterday at 07:10 AM On 10/6/2025 at 8:41 AM, Kas Ob. said: CreateAnonymousThread is mute and return a class that can not be extended, so fundamentally is wrong to return a class that has dangerous publics, it should return a class that can't be abused, right ? First of all, TThread is a very old class. It is an abstract class and it needs to have its features available to the descendants. Because it is old, some of the added features might have not been there from the start and there may have been constraints on how the class could be extended. Also, you cannot use configurable properties unless you have a reference and once you have a reference you cannot easily say it shouldn't be used. And because of C++ Builder integration you cannot have overloaded constructors. So, making TThread and some of its descendants more fool proof would have negative impact on all code which uses it. Now, some additional protection could be implemented without adding too much cruft, but that could also have impact on how one can use the whole TThread class and its flexibility. And at the end of the day, any such measures you can implement on the base class, could be easily rendered useless in the descendant classes. So you would be back at the square one as developers can easily shoot themselves in the foot if they have never read the documentation. I guess that trying to protect what is basically unprotectable was never deemed too important because it would be mostly futile endeavor, and threading is a more advanced feature which requires some knowledge anyway or one can make a huge mess from which nobody can protect you. The behaviors are documented and all what is needed is reading the documentation. 3 Share this post Link to post
Remy Lebeau 1674 Posted yesterday at 08:44 AM 1 hour ago, Dalija Prasnikar said: And because of C++ Builder integration you cannot have overloaded constructors. Yes, you can, as long as they have different signatures. What you can't have is Delphi-style named constructors that have the same signature. Share this post Link to post
Kas Ob. 160 Posted yesterday at 09:25 AM 1 hour ago, Dalija Prasnikar said: On 10/6/2025 at 9:41 AM, Kas Ob. said: CreateAnonymousThread is mute and return a class that can not be extended, so fundamentally is wrong to return a class that has dangerous publics, it should return a class that can't be abused, right ? First of all, TThread is a very old class. It is an abstract class and it needs to have its features available to the descendants. Because it is old, some of the added features might have not been there from the start and there may have been constraints on how the class could be extended. Well, that wasn't the my point, my point is TAnonymousThread and TThread should be different classes, as they have some shared functionality and usage, but also allowing abuse, CreateAnonymousThread should returned a different class lets say TAnonThread that has internally TThread as hidden (private not even protected) field, this way better and prevent problems and even the reason of this very thread. As for WaitFor should raise an exception, it should, the whole TThread is over engineered and riddled with these dangerous functionality, and yes it is powerful and flexible, as it should, i am not saying otherwise, all what i am saying it need rehulling and more protecting. as example, Why we have TThread.Resume and TThread.Start, they both resume a thread from suspend state, only Start check for suspended or not and might/can raise exception while Resume will not raise exception, and in this very case there is zero chance to cause hang or freeze, while with WaitFor there is no check or protection. ( well i don't these are beyond Delphi XE8) 2 hours ago, Dalija Prasnikar said: Also, you cannot use configurable properties unless you have a reference and once you have a reference you cannot easily say it shouldn't be used. And because of C++ Builder integration you cannot have overloaded constructors. So, making TThread and some of its descendants more fool proof would have negative impact on all code which uses it. Now, some additional protection could be implemented without adding too much cruft, but that could also have impact on how one can use the whole TThread class and its flexibility. And at the end of the day, any such measures you can implement on the base class, could be easily rendered useless in the descendant classes. So you would be back at the square one as developers can easily shoot themselves in the foot if they have never read the documentation. Yes we can't, yet we can enforce best practice by raising exceptions, these to prevent the might work now, and force the developer to rethink, WaitFor with FreeOnTerminated=True is beyond dangerous and wrong, risky is the not the word here. 2 hours ago, Dalija Prasnikar said: I guess that trying to protect what is basically unprotectable was never deemed too important because it would be mostly futile endeavor, and threading is a more advanced feature which requires some knowledge anyway or one can make a huge mess from which nobody can protect you. The behaviors are documented and all what is needed is reading the documentation. Futile !? Threading is advanced and need knowledge, yet decreasing the breaking points and put at safety on loaded foot gun, is better than having bad RTL design and call it for expert use only. As for the documentation then it should be in red bold font in every property and method of TThread, in case FreeOnTerminate is True and the Thread is running then never access this xxxxx Not even suspend should be accessed, nothing, and you should have invalidate any variable holding this Thread. Share this post Link to post
Dalija Prasnikar 1570 Posted yesterday at 11:45 AM 2 hours ago, Remy Lebeau said: Yes, you can, as long as they have different signatures. What you can't have is Delphi-style named constructors that have the same signature. Yes, but that makes usage of such classes more convoluted on the Delphi side. Share this post Link to post
Kas Ob. 160 Posted yesterday at 12:51 PM I remembered another critical bug and design flaw in TThread.Create, this one has very bad consequences, this bug according to my XE8 and don't if it is still there in newer versions, but i am familiar with this bug since 10 years, and it might be the time to report it here and if it is still exist then it should be fixed. GetCurrentThread is used in one place inn system.pas, (again, that according to my XE8), and it is in TTHread.Create, when it will be called if the thread is TExternalThread, GetCurrentThread is beyond dangerous if used wrongly and the designer of the RTL missed the documentation of it. From https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthread Quote Return value The return value is a pseudo handle for the current thread. Remarks A pseudo handle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to specify itself whenever a thread handle is required. Pseudo handles are not inherited by child processes. This handle has the THREAD_ALL_ACCESS access right to the thread object. For more information, see Thread Security and Access Rights. Windows Server 2003 and Windows XP: This handle has the maximum access allowed by the security descriptor of the thread to the primary token of the process. The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function. And as a fact GetCurrentThread always return fixed value (constant) equal to $FFFFFFFE, and here its code form the kernel itself KERNEL32.GetCurrentThread: 7639EA50 6AFE push $fe 7639EA52 58 pop eax 7639EA53 C3 ret That is it, and it in the user mode part in the kernel, so any API called on that returned value will apply to the caller ! If you WaitFor an ExternalThread then the caller thread will be waiting on itself and will hang, if a thread Suspend that Value the caller will be suspending itself, and if thread call TerminateThread with that Value it will terminate the caller, iin this case if the caller is the main thread then the process will be terminated right then and there. ps: a confirmation if this design still exist in the latest will be nice. Share this post Link to post