I'm studying these two examples from these questions
- Pausing-a-thread-with-a-property (Remy's Answer).
- Do I need TThreads? If so can I pause, resume and stop them? (LU RD Answer).
What techniques I was using to debug?
Read the code and speculate how it is going to fail.
Compile the code and let it run and see if I'm right.
That got me to find a bug in the second answer. This was my comment:
The example you have shown has a bug: If you let the task finish it will show task terminated on the label and not task done because you are calling
btnCancelTaskClick(Self);
after the label's caption is set to task done which will destroy the thread which will wake up the cancel event and breaks the loop resulting in posting the second message which will change the caption to task terminated. the solution would be to add this lineif not readyFlag then
before the call of the secondpostmessage
. I have suggested an edit I hope you do not mind
What techniques am I using now?
- First techniques.
- Put break points everywhere and press Ctrl + Alt + T to see the stat of each thread.
Now here were things start showing its ugly side. I come to understand that threads run in a non synchronized way (which runs first will remain a ???). and these are the results I got from the first answer.
Example to reproduce
Create a new VCL project and add two TButtons on the main form. The first button creates the thread an the second one frees it.
procedure TForm6.Button1Click(Sender: TObject);
begin
th.Free;
end;
procedure TForm6.Button2Click(Sender: TObject);
begin
th := TMyThread.Create;
end;
press Button2 then Button1 and see what you can get
Results (under debugger):
In the first run I got GetLastError = 6 = ERROR_INVALID_HANDLE. strangely the result of the
TEvent.WaitForMultiple
was notwrAbandoned
when the TEvent was destroyed in the Destructor from the main thread (the main thread is the one executing the destroy code).In the second run I got nothing and the thread was terminated properly.
- In the third run the code stuck on the CheckPause method, because the
TEvent.WaitForMultiple
returnedwrAbandoned
and it kept looping inside until terminated was True.
When launching the second answer without the debugger nothing happened for 10 runs.
Conclusions: I admit debugging a multi-threaded application is a nightmare. The best way I can design a proper non deadlocking free of bugs class is also a nightmare.
Checking for terminate will be my mode from now.
The errors I get in the debugger are not present always when I launch the code out of it (no idea why? I checked if the exceptions are swallowed some where else but with no success).
Question How can I improve the debugging process in a Delphi multithreaded code? So I get more of these errors.