View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0004117 | JEDI VCL | 00 JVCL Components | public | 2007-04-29 00:01 | 2007-11-18 04:23 |
Reporter | adit_bose | Assigned To | jfudickar | ||
Priority | normal | Severity | major | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Product Version | |||||
Target Version | Fixed in Version | ||||
Summary | 0004117: Bug in JvThread | ||||
Description | I've used JvThread in my application. While using it, I've found a bug in the ThreadTerminate method, that can be seen in the attached program. On calling JvThread.Terminate after ThreadExecute or ThreadExecuteAndWait, it does NOT terminate. It is Terminated by passing a boolean value (QuitThread). | ||||
Additional Information | The thread is Terminated by passing a boolean value (QuitThread), but this is not the proper way to terminate the thread because, this sample program instantiates on a loop, what if there is no loop? | ||||
Tags | No tags attached. | ||||
2007-04-29 00:01
|
ThreadBugSource.zip (361,759 bytes) |
|
Can you elaborate a bit more on this? From the description I have a hard time understanding what the problem is. |
|
To reporter (adit_bose): You incorrectly treat action of a method 'Terminate'. This method doesn't 'stop' the thread but only sets 'Terminated' flags for all threads in internal list (like TThread.Terminate does it). Thread should check 'Terminated' and stop execution itself: procedure TForm1.JvThread1Execute(Sender: TObject; Params: Pointer); begin // repeat until QuitThread = true; repeat {...} until JvThread1.Tetrminated; // conventional use end; Method TJvThread.Tetrminated scans all thread in internal list, finds current thread and returns it's 'Terminated' flag. |
|
Thx obones and AlexB for taking interest in the query. What I want to assert, is that on calling Terminate, a thread should immediately stop running. But this does not happen, as shown in the zip file example. For example, if we close an application with running thread, it will raise an exception. To counter this, what should have happened, is that the thread should have terminated (stopped running) if we had called Terminate before closing the application, but unfortunately, even if Terminate is called on ApplicationClose, and the thread is running; the thread does not close, and raises exception. To understand it better, do something like this : 1. Run a thread, and in its execute event, run an infinite loop. 2. In the close event of the application, call Thread.Terminate. In step 2, the thread should have terminated and then the application should have closed normally, but this raises an exception. The problem is, that Terminate call should have FORCE terminated the thread even if the loop inside the thread was running. I agree with AlexB that Terminate sets the 'Terminated' flags in the internal list, but is it really what it was supposed to do ? Please refer to details of TerminateThread in MSDN, the problem may be there ??? |
|
Hi ad_bose! > I agree that Terminate sets the 'Terminated' flags in the internal list, but is it really what it was supposed to do ? Please refer to details of TerminateThread in MSDN, the problem may be there ??? ----- 'Terminate' is only name of method, it's particular action you can easily see in our _open_ source. TJvThread.Terminate has the same name as VCL TThread.Terminate and works similarly. I aree that name is not so good (in terms of MS 'TerminateThread') but (as you understand) it was not our choice. Please see more information about use of VCL class TThread in help for D7/BCB6. > The problem is, that Terminate call should have FORCE terminated the thread ----- Ask Borland/CG why TThread.Terminate only sets flag :) If you know TThread has no method for true termination of thread at all (you still can do it directly via TThread.Handle but you should know what you do). >1. Run a thread, and in its execute event, run an infinite loop. 2. In the close event of the application, call Thread.Terminate. In step 2, the thread should have terminated and then the application should have closed normally, but this raises an exception. ----- Brutal termination is not welcome. Gentle finishing of thread requires cooperation between main thread and background thread: main thread sets the flag and waits, background thread must finish its execution if flag is true; it's the conventional way and it's the way how VCL TThread class works. Complete example of finising of application you can see in Examlpes\JvThread\BCB\fThread.cpp: void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose) { // set flag 'Terminated' for all threads and resume of all threads JvThread->Terminate(); // wait for finish of all threads JvThread->WaitFor(); // if you used JvThread->FreeOnTerminate=false if(JvThread->Count) JvThread->RemoveZombie(); } ------ Alex |
|
Here can be resolution like "Thread.TerminateHard" like in one component (i dont remember where) was. So this method must terminate and free Thread memory. Is this acceptable? |
|
Thx Alex and ZENsan for your time. The problem still remains the same, despite all the explanations. However ZENsan, if you can provide me with the component you mentioned, or its source, it may be worth experimenting over it. Thx again, both of you. |
|
Why dont use TerminateThread for this extraordinal situations? Call this method like TerminateHard. TerminateThread(hThread, EXIT_CODE); |
2007-07-16 06:43
|
Thread.zip (2,040 bytes) |
|
There is also primitive sample for Thread. |
|
Idea: Thread.Terminate must look like something this: ... QuitThread := True; Time := 0; repeat Time := Time + 10; Sleep(10); until Terminated or Time >= TimeOut; if not Terminated then if not TerminateThread(Handle, EXIT_CODE_HARD_TERMINATE) then raise JvThreadException.Create('Failed to terminate thread. Thread is blocked.'); ... |
|
Thx very much again ZENsan, for the idea and for the time. To understand the problem better, I'll try to explain the theory now. Please let me know, where I’m going wrong, or if my perseverance is correct. I've used TerminateThread already, but unfortunately that does not work. I've already mentioned it in this sequence of messages (plz search in this web page - "Please refer to details of TerminateThread in MSDN, the problem may be there ???") Anyway, I'll now try to explain the scene, the problem, that is. Suppose that our program is supposed to destroy a particular "target" window, identified by its window handle (obtained by, say, FindWindow). This target window can appear many times. Now, I run an infinite loop in a thread (made to execute at FormCreate) in which the code to destroy the target window is put. This code to destroy the window is continuously run in a loop. The target window can show up any number of times, and hence the presence of "infinite" loop. This thread is supposed to continuously run till the program ends (FormClose). Of course a timer can be a good substitute, but right now, we are taking thread. What I’ve tried to do earlier is that on FormClose, I used TerminateThread, and/or all sorts of methods to close the thread (not loop, let's be specific), but in all cases it raised error (exception) after application closed, because the thread (ok, loop) did NOT terminate, despite any call to terminate the thread. If we call "Halt" in our application at FormClose, still there is error (exception). Now I solved it "conditionally" by using a local Boolean variable and that was made to toggle at FormClose, and hence triggered the closure of the loop in the thread. This way the thread was "made to terminate". I'm giving the sample code of "HideMsg" thread, and then later discuss the outcome. Here's the code : // on FormCreate, HideMsg.Execute is called var ExitLoop : bool; //(declared in Private, and initialized in FormCreate as False) procedure TForm1.HideMsgExecute(Sender: TObject; Params: Pointer); var i : HWND; begin repeat i := FindWindow(nil, PChar('SomeWindow')); if i <> 0 then SendMessage(i, WM_Close, 0, 0); // or WM_NCDESTROY until ExitLoop = true; end; Now, at FormClose, ExitLoop is set to True (which was otherwise False throughout the running of application), and hence the loop closed immediately and the thread terminates correctly. What I want to assert is that is there NO OTHER WAY to close the THREAD (even if the loop is running) WITHOUT calling ExitLoop, that would NOT raise exception otherwise. There are different methods, that "look" as if it would "force close" the thread, like "TerminateThread", "HideMsg.Terminate" etc, but all are hopeless for this purpose. What is the use of "TerminateThread", "HideMsg.Terminate" etc, when they can't actually terminate the thread. Note that in my example, I’ve used a loop. But looking at it in a broader spectrum, the same problem may exist in non-loop cases too. Also, as mentioned earlier, if we "Halt" our application at FormClose, still there is error (exception). Now, let's close in more : Why does Windows not raise exception, if we close our application through Windows Task Manager. How can Windows close the loop/thread, without exception? Normally, on FormClose, it may raise exception... granted; but why calling "Halt" raises exception? Perhaps we may not like to compare "Halt" with "EndProcess" in Windows Task Manager, as "Halt" is used as an internal application command, and Windows Task Manager being an entirely separate process, but I presume, even on contrasting them, "Halt" should have closed the THREAD without exception, as Windows Task Manager. Now, that we are observing this bug under microscope, I hope I'm able to put the case better now. If there is any provision to suppress the exception by any means, then it is ok; for example, using compiler directives, like {$I-} etc, else there is perhaps some "broken link" between Microsoft-Borland-Jedi. I know, it is perhaps against "good" programming coding, but very often we are faced by such circumstances, where we are forced to employ codes for 'unseen' or 'unpredictable' events, else there would not have been "EndProcess" in Windows Task Manager. |
|
So what's the result of this? Any actions to be taken? |
|
IMO the resolution is "as designed". The sense of the complaint is "Method Terminate doesn't terminate the thread but sets the flag only". But this is well-known behavior of the TThread and TJvThread is only container of the TThread's descendants. If you need to terminate the thread you should call Terminate (set the flag) and wait for thread completion; the class TThread initially does not give a way for forced end of the thread. |
|
The only think we could do is a new procedure terminate_and_wait. This could call terminate and then do a loop until all threads are finished. Not the best solution, but maybe sometimes helpfull. Greetings Jens |
|
OK, if so then such method should look like FormCloseQuery in example for BCB (as was already described in one of my previous posts (0013528) AlexB 06-24-07 02:18 edited on: 06-24-07 02:40): //--------------------------------------------------------------------------- void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose) { JvThread1->Terminate(); JvThread1->WaitFor(); if(JvThread1->Count) JvThread1->RemoveZombie(); } //--------------------------------------------------------------------------- |
|
Added to svn TJvThread.TerminateWaitFor |
Date Modified | Username | Field | Change |
---|---|---|---|
2007-04-29 00:01 | adit_bose | New Issue | |
2007-04-29 00:01 | adit_bose | File Added: ThreadBugSource.zip | |
2007-04-30 01:27 | obones | Relationship added | has duplicate 0004118 |
2007-06-19 09:20 | obones | Note Added: 0013470 | |
2007-06-19 09:20 | obones | Status | new => feedback |
2007-06-20 22:36 | AlexB | Note Added: 0013506 | |
2007-06-21 21:35 | ad_bose | Note Added: 0013509 | |
2007-06-24 02:18 | AlexB | Note Added: 0013528 | |
2007-06-24 02:39 | AlexB | Note Edited: 0013528 | |
2007-06-24 02:40 | AlexB | Note Edited: 0013528 | |
2007-06-25 02:44 | ZENsan | Note Added: 0013536 | |
2007-06-30 21:53 | adit_bose | Note Added: 0013544 | |
2007-07-16 06:34 | ZENsan | Note Added: 0013579 | |
2007-07-16 06:43 | ZENsan | File Added: Thread.zip | |
2007-07-16 06:44 | ZENsan | Note Added: 0013580 | |
2007-07-16 06:51 | ZENsan | Note Added: 0013581 | |
2007-07-16 06:54 | ZENsan | Note Edited: 0013581 | |
2007-07-18 10:45 | adit_bose | Note Added: 0013592 | |
2007-07-18 10:52 | adit_bose | Note Edited: 0013592 | |
2007-07-18 10:56 | adit_bose | Note Edited: 0013592 | |
2007-07-18 10:59 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:06 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:10 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:10 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:13 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:16 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:18 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:27 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:30 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:36 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:47 | adit_bose | Note Edited: 0013592 | |
2007-07-18 11:58 | adit_bose | Note Edited: 0013592 | |
2007-07-18 12:12 | adit_bose | Note Edited: 0013592 | |
2007-10-12 07:11 | obones | Note Added: 0013923 | |
2007-10-14 22:26 | AlexB | Note Added: 0013962 | |
2007-10-15 02:06 | jfudickar | Note Added: 0013963 | |
2007-10-15 05:58 | AlexB | Note Added: 0013968 | |
2007-10-15 06:02 | AlexB | Note Edited: 0013968 | |
2007-10-15 06:02 | AlexB | Note Edited: 0013968 | |
2007-10-16 01:47 | jfudickar | Status | feedback => assigned |
2007-10-16 01:47 | jfudickar | Assigned To | => jfudickar |
2007-11-18 04:21 | jfudickar | Status | assigned => resolved |
2007-11-18 04:21 | jfudickar | Resolution | open => fixed |
2007-11-18 04:21 | jfudickar | Note Added: 0014031 |