I have a thread called TMyThread and I overrode the Execute procedure like this:
procedure TMyThread.Execute;
Begin
repeat
//Some Work
Sleep(50
You really are approaching this problem completely wrong. Code your threads to only do work that you want them to do, and then there will be no need to "reach in from the outside" to control them. You feel the need to control this thread from the outside because it's doing something you don't want it to do -- well then why did you code it to do that in the first place?
Your thread's Execute
method must regularly check the state of the thread's Terminated
property. And if it is True
, then the thread Execute
method must exit.
So, a typical Execute
method might look like this:
procedure TMyThread.Execute;
begin
while not Terminated do
DoNextPieceOfWork
end;
It looks like your thread has its own FActive
flag that is performing the same task. The problem with that is that TThread
doesn't know about it. So you should get rid of FActive
and instead use the built in mechanism.
When you call Free
on the thread it will call Terminate
. That sets Terminated
to be True
. Then it waits for the thread method to exit. That will happen because your thread notices that Terminated
is True
and quits. And then the thread's destructor can continue and finish the job of tidying up the thread.
Looking at the code in your answer, it would be better written to make use of the existing Terminate
mechanism.
type
TMyThread = class(TThread)
private
FTerminateEvent: TEvent;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create(ACreateSuspended: Boolean);
destructor Destroy; override;
end;
constructor TMyThread.Create(ACreateSuspended: Boolean);
begin
inherited Create(ACreateSuspended);
FTerminateEvent := TEvent.Create(nil, True, False, '');
end;
destructor TMyThread.Destroy;
begin
inherited;
FTerminateEvent.Free;
end;
procedure TMyThread.TerminatedSet;
begin
FTerminateEvent.SetEvent;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
// do somthing interesting!
FTerminateEvent.WaitFor(5000);
end;
end;
Now there's no need for a separate Stop
method. You can just call Free
on the thread. Then Terminate
is called. And then TerminatedSet
is called. Then the event is signaled. Then Execute
terminates. And then the thread can go away.
Having said that, I'm struggling to think of a scenario where a 5000ms timeout would be the best approach. I don't know why you are doing this, but I'd guess that you are trying to throttle the thread so that it doesn't run hot. You want to avoid a busy loop. That's admirable, but using a fixed timeout is not the way to do it. The way to do it is to wait on a synchronisation event, typically an event. Then when there is more work to be done, the event becomes signaled and your thread wakes up.
Using TEvent can solve this problem this is an eg :
uses SyncObjs;
TMyThread = class(TThread)
private
FTerminateEvent: TEvent;
protected
procedure Execute; override ;
public
constructor Create(ACreateSuspended: Boolean); overload;
destructor Destroy; override;
procedure Stop;
end;
constructor TMyThread.Create(ACreateSuspended: Boolean);
begin
FTerminateEvent := TEvent.Create(nil, True, False, 'FTerminateEvent');
inherited Create(ACreateSuspended);
end;
destructor TMyThread.Destroy;
begin
FTerminateEvent.Free;
inherited;
end;
procedure TMyThread.Stop;
begin
Terminate;
FTerminateEvent.SetEvent;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
// do somthing interesting!
FTerminateEvent.WaitFor(5000);
end;
end;
Now if i want to kill my thread ,all what i have to do is calling MyThread.Stop than calling MyThread.Free .