2017-01-19 82 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作为例子。如果你想。他只是不想为每个任务派生一个新班级。 –

相关问题