2017-01-19 86 views
1

說我有一個對象,在我的情況下TThread,我想檢查它的動態屬性之一,在這種情況下,TThread.Terminated。如何將動態屬性作爲參數傳遞給函數?

是否有一種乾淨的方式來傳遞「屬性」,使得我實際上傳遞了getter函數,並且可以爲此動態檢查該屬性的值?

更多細節:

我的具體問題是,我在Delphi中實現線程的第一次。我並不喜歡標準的Delphi線程實現似乎是爲了創建一個自定義的線程類來執行你想要線程化的方法。我發現了一個令人滿意的解決方案,它使用委託來定義要執行的方法,然後在創建時將實際的方法傳遞給線程對象,從而更好地分離/封裝線程代碼以及由線。下面的細節。

但是,我發現上述想法的實現使用TThread.Suspend來允許提前終止正在執行的方法。 Delphi文檔將TThread.Suspend標記爲不推薦,並且建議長時間運行的方法應檢查Terminated屬性,以便在父線程請求時允許提前終止。因此,我需要一種方法將TThread.Terminated引用傳遞給正在執行的方法,以便該方法可以實現它自己的提前終止。

我無法使用var語法通過引用傳遞屬性。 我無法通過引用傳遞底層FTerminated字段,因爲它是TThread的私有成員。 我知道我只需將TThread對象的引用傳遞給該方法,但該類型的循環引用看起來像是解決問題的一種方法。

那麼,有沒有'接受'的方式來動態傳遞一個屬性,或者我堅持我目前的方法?

目前代碼: 接口

uses 
    Windows, Messages, Classes, Forms; 

type 
    // Method Thread Will Execute. Acts on Data. Runs in RunningThread. 
    // (Reference to RunningThread is past so method can check runningthread.terminated 
    // to allow long running methods to terminate early when parent thread requests it) 
    TThreadMethod = procedure (Data: pointer; RunningThread: TThread) of object; 
    //A Simple Thread Which Excecutes a Method on Some Data 
    TSimpleThread = class(TThread) 
    protected 
     Method: TThreadMethod; 
     Data: pointer; 
     procedure Execute; override; 
    public 
     constructor Create(Method: TThreadMethod; Data: pointer; CreateSuspended: boolean); overload; 
    end; 

implementation 
    // SimpleThread 
    constructor TSimpleThread.Create(Method: TThreadMethod; 
           Data: pointer; 
           CreateSuspended: boolean); 
    begin 
    Self.Method := Method; 
    Self.Data := Data; 
    inherited Create(CreateSuspended); 
    Self.FreeOnTerminate := True; 
    end; 

    procedure TSimpleThread.Execute(); 
    begin 
    Self.Method(Data, Self); 
    end; 
+0

有你的線程類實現一個你傳入你的線程執行方法的接口。 –

+0

- *「我不能通過引用傳遞底層FTerminated字段,因爲它是TThread的私有成員。」* - 不是我推薦的,但是,您可以像getter只讀字段。請參閱[本文]下的討論(http://stackoverflow.com/questions/25666626/delphi-change-main-form-while-application-is-running)。 –

回答

4

說我有一個對象,在我的情況下TThread類,我要檢查它的一個動態的屬性的功能,在這種情況下TThread.Terminated 。

處理,最好的辦法是從TThread派生新類並覆蓋其虛擬Execute()方法來直接運行你的線程代碼,然後在需要時的代碼可以訪問該對象的Terminated屬性。就像你的例子所做的那樣。

如果你的線程代碼不能在Execute()放在直接(比如,你正在使用TThread.CreateAnonymousThread()TTask代替),在那裏你可以不是原來的TThread對象指針直接傳遞給線程的程序,沒有失去一切。 TThread有一個CurrentThread類屬性來訪問運行調用代碼的TThread對象。當TThread開始運行時,它將其Self指針存儲在屬性隨後訪問的thread變量(因此每個線程上下文都獲取其自己的變量副本)中。

但是,你的問題被標記爲Delphi 7,它不支持匿名程序,匿名線程或任務,所以你基本上手動將你的TThread對象傳遞給你的程序代碼。如果您不想將對象指針作爲過程參數傳遞,則可以使用自己的thread變量。

是否有一個乾淨的方式來傳遞'屬性',使得我實際上傳遞了getter函數並且可以爲此動態檢查該屬性的值?

對於初學者來說,有沒有吸功能,Terminated屬性指示返回FTerminated成員,這是private反正。您需要實際的TThread對象指針才能讀取Terminated屬性。

傳遞FTerminated成員本身的指針/引用的唯一方法是使用Extended RTTI,這在Delphi 7中不存在。所以這對您沒有幫助。 Delphi 7中的舊RTTI不夠豐富,無法訪問FTerminated成員。

然而,我發現上述想法的實現使用TThread.Suspend允許提前終止正在執行的方法。

然後你正在做一個糟糕的實現。

除非您指的是TThread構造函數的ACreateSuspended參數,它完全可以安全使用。如果將其設置爲True,則線程不會被創建並暫停,而會以暫停狀態創建。當您準備在創建線程後啓動線程時,您只需撥打Resume()(或在以後的Delphi版本中使用Start())。

否則,只需將ACreateSuspended設置爲False,並讓它在所有構造函數退出後自動啓動。

德爾福文檔標記TThread.Suspend爲過時

這是正確的。 Suspend()從線程外部使用永遠不會安全,因爲其他線程無法確保線程處於安全狀態而被暫停。 Suspend()只有在線程從其自己的Execute()方法中掛起時纔可以使用,因爲只有該線程纔會知道何時可以安全地執行掛起。但即使如此,通常有更好的方法來實現線程掛起而不實際使用Suspend()(而不是等待TEvent)。

因此,我需要一種方法來傳遞TThread.Terminated引用到它正在執行的方法,以便該方法可以實現它自己的提前終止。

不,您需要將參考TThread對象本身傳遞給您的過程,而不是對任何特定屬性的引用。

我無法使用var語法通過引用傳遞屬性。我無法通過引用傳遞底層的FTerminated字段,因爲它是TThread的私人成員。

正確。

我知道我只需將TThread對象的引用傳入方法中,但該類型的循環引用看起來像是解決問題的一種方法。

這是唯一的方法,如果你想使用TThread.Terminated屬性。

否則,根本不要使用TThread.Terminated。改用你自己的信號機制。 Terminated屬性只是一個Boolean標誌,僅此而已。它被提供爲便利,而不是要求。您可以使用任何想要的信號來指示您的過程退出,並使線程自行終止。

那麼,有沒有'接受'的方式來動態傳遞一個屬性,或者我堅持我目前的方法?

當前的方法基本上是你必須做什麼,尤其是在Delphi 7.對於以後的Delphi版本中,你基本上是重新創建什麼TThread.CreateAnonymousThread()呢,比如:

TThread.CreateAnonymousThread(
    procedure 
    begin 
    MyMethod(MyData, TThread.CurrentThread); 
    end 
).Start; 
+0

他想創建自己的'CreateAnonymousThread'版本。完全可能。甚至不需要從'TThread'派生。 –

+0

你爲什麼認爲不需要派生類? 'TThread'不支持在沒有'CreateAnonymousThread()'的Delphi版本中運行用戶提供的方法。 –

+0

您可以使用BeginThread作爲例子。如果你想。他只是不想爲每個任務派生一個新班級。 –

相關問題