2014-01-10 74 views
3

考慮以下類:自定義線行爲不端

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; 

當主窗體調用InstanceVar := EventTitle.Create自動線程應達到的方法CreateSprite,什麼古怪的是沒有發生。我不明白爲什麼該方法沒有被執行。該應用程序的主要形式仍然正常工作,但它似乎像EventTitle.Execute突然停止,甚至不啓動。它可能也是錯誤實現。這是我的第一個多線程試用版,然後對任何不一致性抱歉。任何人都可以看到我做錯了什麼?

+0

OT:不要使用暫停和恢復。當編譯器在警告中報告你時,它們已被廢棄......同時創建線程作爲立即恢復的暫停狀態看起來並不太有用。 – TLama

+0

真的。我會讓'Resume'給子線程。刪除它...... – Guill

+0

也許使用OmniThreadLibrary對你來說比對TThread內部進行挖掘更容易 –

回答

5

這裏有一些明顯的問題。我不知道,修復它們能夠解決您的問題,但我也不會感到驚訝:

  1. Execute方法必須與override聲明爲它運行。這解釋了你報告的行爲。
  2. 您的析構函數必須聲明爲override才能運行。請注意,你實現了GEvent.Destroy,但GEvent類沒有聲明析構函數。所以問題中的代碼不能編譯。在線程類的析構函數中不要調用Terminate。基類析構函數TThread.Destroy終止並等待該線程。取消撥打電話TerminateGEvent.Destroy。您的Terminate方法隱藏TThread.Terminate。這是非常糟糕的做法。我確信編譯器會警告你。你必須注意警告。按照它的規定,線程的析構函數暫停線程,然後等待它完成。你最好希望線程在你銷燬它的時候已經完成了執行。
  3. 創建一個線程僅僅是爲了立即恢復它是沒有意義的。雖然沒有真正的問題會由此造成的。
  4. GEvent.Call中的代碼完全是假的。永遠不要分配到Self。您必須刪除該代碼。
  5. 您撥打Suspend的所有電話都是錯誤的。您不能撥打Suspend。它有不可預知的結果。刪除對Suspend的呼叫。

您所犯的重複錯誤是遺漏了override。該關鍵字用於覆蓋虛擬方法。在Execute方法和析構函數的情況下,這些是由基類調用的虛擬方法。因此,如果您不覆蓋虛擬方法,則只需在派生類中引入新方法即可。當基類調用虛擬方法時,您的新方法將不會執行。

我建議在開始使用此代碼:

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; 

我已經去掉了幾乎所有的代碼,但幾乎所有的這是不對的。

+0

1.好吧。 2.「GEvent」將有許多孩子;其中一些可能需要一些初始化的東西。但是,這裏也一樣。 3。此代碼引用另一個具有「GEvent」屬性的類。這個屬性會在使用'Call'方法的事件之間改變,但我正在努力去除那條線。這不是問題的原因。 4.所有「暫停」呼叫被移除。問題依然存在。 – Guill

+0

答案已更新。閱讀新的項目1. –

+0

我猜'Override'丟失了。曾經我認爲我不需要在孩子身上做的「GEvent」課程。我還沒有在關於Delphi的Threading的頁面中找到這個慣例。他們是非常必要的。無論如何,謝謝你,先生。我接受你的答案。我還不能投票,所以... – Guill