Custom Thread misbehaving
-
22-12-2019 - |
Question
Given the following classes:
type
GEvent = class(TThread)
public
procedure Terminate;
procedure Call(Event : GEvent);
constructor Create;
procedure Execute; Override;
end;
TDirection = (DUp, DRight, DDown, DLeft);
EventTitle = class(GEvent)
private
Index : Integer;
Sprite : CSprite;
Terminate : Boolean;
procedure CreateSprite;
procedure MoveCursor(Direction : TDirection);
procedure RefreshCursor;
constructor Create;
destructor Destroy;
public
procedure Execute;
end;
implementation
{ GEvent }
procedure GEvent.Call(Event: GEvent);
begin
Suspend;
// inherited Terminate;
Self := GEvent(Event.ClassType.Create);
end;
constructor GEvent.Create;
begin
inherited Create(True);
end;
destructor GEvent.Destroy;
begin
Terminate;
inherited;
end;
procedure GEvent.Execute;
begin
// inherited;
end;
procedure GEvent.Terminate;
begin
Suspend;
inherited;
end;
{ EventTitle }
constructor EventTitle.Create;
begin
inherited;
Resume;
end;
procedure EventTitle.CreateSprite;
begin
Showmessage('anything');
end;
destructor EventTitle.Destroy;
begin
inherited;
end;
procedure EventTitle.Execute;
begin
inherited;
Synchronize(CreateSprite);
Index := 0; {
while not Terminated do
begin
if GISystem.System.Input.Trigger(KUp) then
MoveCursor(DUp);
if GISystem.System.Input.Trigger(KDown) then
MoveCursor(DDown);
end; }
end;
When main form calls InstanceVar := EventTitle.Create
automatically the Thread should reach the method CreateSprite
, what weirdly is not happening. I could not figure why the method is not being executed. The main form of the application still works fine but it seems like the EventTitle.Execute
stops abruptly or even do not start. It maight be misimplementation as well. It is my first MultiThreading trial, then sorry for any inconsistence. Can anyone see what I did wrong?
Solution
There are some obvious problems here. I'm not sure that fixing them will resolve your problem, but I would not be surprised:
- Your
Execute
method must be declared withoverride
for it to run. This explains the behaviour that you report. - Your destructor must be declared with
override
for it to run. Note that you implementGEvent.Destroy
but theGEvent
class does not declare a destructor. So the code in the question does not compile. - Do not call
Terminate
in the destructor of a thread class. The base class destructorTThread.Destroy
terminates and waits for the thread. Remove the call toTerminate
inGEvent.Destroy
. - Your
Terminate
method hidesTThread.Terminate
. That is really bad practice. I'm sure the compiler warns you of this. You must heed the warnings. As it stands your thread's destructor suspends the thread and then waits for it to finish. You had better hope that the thread has already finished executing by the time you destroy it. - It is pointless to create a thread suspended only to immediately resume it. Although there's no real problem that will be caused by that.
- The code in
GEvent.Call
is utterly bogus. Never assign toSelf
. You must remove that code. - All your calls to
Suspend
are wrong. You must not callSuspend
. It has unpredictable results. Remove the calls toSuspend
.
A repeated error that you have made is the omission of override
. That keyword is used to override a virtual method. In the case of the Execute
method, and the destructor, these are virtual methods called by a base class. As such, if you do not override the virtual method, you are simply introducing a new method in the derived class. And when the base class calls the virtual method, your new method will not execute.
I suggest that you start with this code:
type
EventTitle = class(TThread)
private
procedure DoSomething;
public
constructor Create;
procedure Execute; override;
end;
implementation
constructor EventTitle.Create;
begin
inherited Create(False);
end;
procedure EventTitle.DoSomething;
begin
ShowMessage('anything');
end;
procedure EventTitle.Execute;
begin
Synchronize(DoSomething);
end;
I've stripped out almost all of your code, but almost all of it was wrong.