假设我有一个对象,在我的情况下是一个TThread,我想在一个函数中动态检查其中一个属性,在本例中为TThread.Terminated。
是否有一种传递'属性'的简洁方法,以便我实际上传递了getter函数,并可以动态检查该属性的值?
更多细节:
我的具体问题是我第一次在Delphi中实现线程化。我不喜欢标准的Delphi Threading实现似乎是创建一个自定义线程类来执行你想要线程化的方法。我找到了一个令人满意的解决方案,其中一个使用委托来定义要执行的方法,然后在创建时将实际方法传递给线程对象,从而允许更好地分离/封装线程代码以及由线。详情如下。
然而,我发现上述想法的实现使用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 :(得分:4)
假设我有一个对象,在我的情况下是一个TThread,我想在一个函数中动态检查其中一个属性,在本例中为TThread.Terminated。
处理这个问题的最好方法是从TThread
派生一个新类并覆盖其虚拟Execute()
方法直接运行你的线程代码,然后该代码可以访问对象' s需要时Terminated
属性。就像你的榜样一样。
如果您的线程代码无法直接放入Execute()
(例如,您使用的是TThread.CreateAnonymousThread()
或TTask
),那么您无法通过原始{{1}对象指针直接指向线程程序,一切都不会丢失。 TThread
具有TThread
类属性,用于访问运行调用代码的CurrentThread
对象。当TThread
开始运行时,它会将TThread
指针存储在Self
变量中(因此每个线程上下文都会获得自己的变量副本),thread
属性随后会访问该变量。
但是,您的问题标记为Delphi 7,它不支持匿名过程,匿名线程或任务,因此您基本上无法手动将CurrentThread
对象传递给您的过程代码。如果您不想将对象指针作为过程参数传递,则可以使用自己的TThread
变量。
是否有一种干净的方式来传递'属性'这样我实际上传递了getter函数,可以动态检查该属性的值吗?
对于初学者,没有getter函数,thread
属性指示返回Terminated
成员,无论如何都是FTerminated
。您需要实际的private
对象指针才能从TThread
属性中读取。
传递指向Terminated
成员本身的指针/引用的唯一方法是使用Extended RTTI,这在Delphi 7中不存在。所以这对你没有帮助。 Delphi 7中的旧RTTI不够丰富,无法访问FTerminated
成员。
然而,我发现上述想法的实现使用
FTerminated
来允许提前终止正在执行的方法。
然后你正在处理一个糟糕的实现。
除非您指的是TThread.Suspend
构造函数的ACreateSuspended
参数,否则使用起来非常安全。如果它设置为True,则不创建线程然后暂停,它将以挂起状态创建以开始。当你准备好在创建线程后启动线程时,你只需要调用TThread
(或后来的Delphi版本中的Resume()
)。
否则,只需将Start()
设置为False,并在所有构造函数退出后让它自动启动。
Delphi文档将TThread.Suspend标记为已弃用
这是正确的。从线程外部使用ACreateSuspended
永远不会安全,因为其他线程无法确保线程处于安全状态以便挂起。 Suspend()
只有在线程从自己的Suspend()
方法中挂起时才可以安全使用,因为只有该线程知道何时执行挂起是安全的。但即使这样,通常有更好的方法来实现线程暂停而不实际使用Execute()
(比如等待Suspend()
)。
因此,我需要一种方法将对TThread.Terminated的引用传递给它正在执行的方法,以便该方法可以实现它自己的提前终止。
不,您需要将对TEvent
对象本身的引用传递给您的过程,而不是对任何特定属性的引用。
我无法使用var语法通过引用传递属性。我无法通过引用传递底层的FTerminated字段,因为它是TThread的私有成员。
正确。
我知道我可以将TThread对象的引用传递给方法,但是这种类型的循环引用似乎是解决问题的一种黑客方式。
如果您想使用TThread
属性,这是唯一的方法。
否则,根本就不要使用TThread.Terminated
。请使用您自己的信号机制。 TThread.Terminated
属性只是Terminated
标志,仅此而已。它以便利提供,而不是要求。您可以使用任何想要表示退出程序的信号以及终止自身的线程。
那么,有没有被接受的'动态传递属性的方法,还是我坚持使用当前的方法?
您当前的方法基本上是您必须要做的,特别是在Delphi 7中。对于后来的Delphi版本,您基本上是在重新创建Boolean
所做的事情,例如:
TThread.CreateAnonymousThread()