【发布时间】:2014-07-18 07:24:19
【问题描述】:
我试图弄清楚如何在库中为使用 Delphi XE5 的移动应用程序实现计时器。此处显示的代码Delphi - timer inside thread generates AV 无法使用,因为我不知道我的库的实例化对象的任何引用以使用同步。
感谢任何帮助
【问题讨论】:
标签: delphi mobile timer delphi-xe5
我试图弄清楚如何在库中为使用 Delphi XE5 的移动应用程序实现计时器。此处显示的代码Delphi - timer inside thread generates AV 无法使用,因为我不知道我的库的实例化对象的任何引用以使用同步。
感谢任何帮助
【问题讨论】:
标签: delphi mobile timer delphi-xe5
这是一个线程计时器,您可以将其用作原始计时器组件 - 但它不是一个组件
uses
...
ThreadTimer;
type
TForm1 = class( TForm )
private
FTimer : TTimerThread;
procedure TimerOnTimer( Sender : TObject );
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
end;
procedure TForm1.AfterConstruction;
begin
inherited;
FTimer := TTimerThread.Create;
FTimer.OnTimer := TimerOnTimer;
// FTimer.Interval := 5000;
// FTimer.Enabled := False;
end;
procedure TForm1.BeforeDestruction;
begin
inherited;
FTimer.Free;
end;
procedure TForm1.TimerOnTimer( Sender : TObject );
begin
// Do whatever you like in here
end;
这里是完整的单元
unit ThreadTimer;
interface
uses
System.Classes,
System.SyncObjs;
type
TTimerThread = class( TThread )
{$REGION 'Constants'}
private const
C_DEFAULT_INTERVAL = 1000;
C_DEFAULT_ENABLED = True;
{$ENDREGION}
{$REGION 'Syncronization'}
private
FCS : TCriticalSection;
FEvent : TEvent;
{$ENDREGION}
private
FInterval : Cardinal;
FOnTimer : TNotifyEvent;
FEnabled : Boolean;
function GetInterval : Cardinal;
procedure SetInterval( const Value : Cardinal );
function GetOnTimer : TNotifyEvent;
procedure SetOnTimer( const Value : TNotifyEvent );
function GetEnabled : Boolean;
procedure SetEnabled( const Value : Boolean );
protected
procedure TerminatedSet; override;
procedure Execute; override;
public
constructor Create;
destructor Destroy; override;
property Interval : Cardinal read GetInterval write SetInterval default C_DEFAULT_INTERVAL;
property OnTimer : TNotifyEvent read GetOnTimer write SetOnTimer;
property Enabled : Boolean read GetEnabled write SetEnabled default C_DEFAULT_ENABLED;
end;
implementation
{ TTimerThread }
constructor TTimerThread.Create;
begin
inherited Create( False );
FCS := TCriticalSection.Create;
FEvent := TEvent.Create( nil, False, False, '' );
FInterval := C_DEFAULT_INTERVAL;
FEnabled := C_DEFAULT_ENABLED;
end;
destructor TTimerThread.Destroy;
begin
inherited;
FEvent.Free;
FCS.Free;
end;
procedure TTimerThread.Execute;
var
LInterval : Cardinal;
begin
inherited;
while not Terminated do
begin
FCS.Enter;
try
if FEnabled
then
LInterval := FInterval
else
LInterval := INFINITE;
finally
FCS.Leave;
end;
if ( FEvent.WaitFor( LInterval ) = wrTimeout )
then
Synchronize(
procedure
begin
if Assigned( OnTimer )
then
OnTimer( Self );
end );
end;
end;
function TTimerThread.GetEnabled : Boolean;
begin
FCS.Enter;
try
Result := FEnabled;
finally
FCS.Leave;
end;
end;
function TTimerThread.GetInterval : Cardinal;
begin
FCS.Enter;
try
Result := FInterval;
finally
FCS.Leave;
end;
end;
function TTimerThread.GetOnTimer : TNotifyEvent;
begin
FCS.Enter;
try
Result := FOnTimer;
finally
FCS.Leave;
end;
end;
procedure TTimerThread.SetEnabled( const Value : Boolean );
begin
FCS.Enter;
try
if FEnabled <> Value
then
begin
FEnabled := Value;
FEvent.SetEvent;
end;
finally
FCS.Leave;
end;
end;
procedure TTimerThread.SetInterval( const Value : Cardinal );
begin
FCS.Enter;
try
if FInterval <> Value
then
begin
FInterval := Value;
FEvent.SetEvent;
end;
finally
FCS.Leave;
end;
end;
procedure TTimerThread.SetOnTimer( const Value : TNotifyEvent );
begin
FCS.Enter;
try
FOnTimer := Value;
finally
FCS.Leave;
end;
end;
procedure TTimerThread.TerminatedSet;
begin
inherited;
FEvent.SetEvent;
end;
end.
【讨论】:
FEvent.Free; FCS.Free; 必须在继承之后。否则,如果线程正在运行并且您调用 Free 继承的析构函数调用 Terminate 并调用 TerminatedSet 并触发事件 - uups,哪个事件......你已经释放它......也在Execute仍在等待事件触发而不是被释放。请通过之前和之后inherited自行检查本单元
TForm1.BeforeDestruction 更改。我无法为带有此类陷阱的代码投票。
inherited 之后)。在 this 的情况下,FTimer 是在 inherited 之前还是之后释放都没有关系。
Free,因为您必须在调用Free 之前调用Terminate,这将是代码异味。别人怎么会知道这个事实。