Filo personalizzato che comporta male.
-
22-12-2019 - |
Domanda
Dato le seguenti classi:
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;
.
Quando la forma principale chiama InstanceVar := EventTitle.Create
automaticamente il thread deve raggiungere il metodo CreateSprite
, che stranamente non sta accadendo.Non riuscivo a capire perché il metodo non viene eseguito.La forma principale dell'applicazione funziona ancora bene, ma sembra che il EventTitle.Execute
si ferma bruscamente o addirittura non iniziare.Essere malintendere anche.È il mio primo processo multithreading, poi mi dispiace per qualsiasi inconsistenza.Qualcuno può vedere cosa ho fatto di sbagliato?
Soluzione
Ci sono alcuni problemi ovvi qui. Non sono sicuro che il fissaggio di loro risolverà il tuo problema, ma non sarei sorpreso:
- .
- Il tuo metodo
Execute
deve essere dichiarato conoverride
per essere eseguito. Questo spiega il comportamento che noti. - Il tuo distruttore deve essere dichiarato con
override
per essere eseguito. Si noti che implementareGEvent.Destroy
ma la classeGEvent
non dichiara un distruttore. Quindi il codice nella domanda non è compilato. - Non chiamare
Terminate
nel distruttore di una classe di thread. Il distruttore di classe baseTThread.Destroy
termina e attende il filo. Rimuovere la chiamata suTerminate
inGEvent.Destroy
. - Il tuo metodo
Terminate
nascondeTThread.Terminate
. Questa è davvero cattiva pratica. Sono sicuro che il compilatore ti avverti di questo. Devi ascoltare gli avvertimenti. Mentre si trova il distruttore del tuo filo sospette il filo e quindi attende che finisca. Hai fatto meglio a sperare che il filo abbia già finito di eseguire il tempo che lo distruggi. - È inutile creare un thread sospeso solo per riprenderlo immediatamente. Sebbene non ci sia un vero problema che sarà causato da quello.
- Il codice in
GEvent.Call
è assolutamente falso. Mai assegnare aSelf
. È necessario rimuovere quel codice. - Tutte le tue chiamate a
Suspend
sono sbagliate. Non è necessario chiamareSuspend
. Ha risultati imprevedibili. Rimuovere le chiamate aSuspend
.
Un errore ripetuto che hai effettuato è l'omissione di override
. Quella parola chiave viene utilizzata per sovrascrivere un metodo virtuale. Nel caso del metodo Execute
, e il distruttore, questi sono metodi virtuali chiamati da una classe base. Come tale, se non si sovrascrive il metodo virtuale, stai semplicemente introducendo un nuovo metodo nella classe derivata. E quando la classe base chiama il metodo virtuale, il tuo nuovo metodo non verrà eseguito.
Ti suggerisco di iniziare con questo codice:
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;
.
Ho spogliato quasi tutto il tuo codice, ma quasi tutto era sbagliato.