在一个旧帖里发现TTimer的小问题,请教一下

yhmeier 2008-07-31 03:55:26
帖子的地址是:
http://topic.csdn.net/u/20070816/19/8e84ef79-5ae3-48c8-8e57-0d912f8e7dc8.html
看到2楼unsigned (僵哥)所说的,有些不明白。请问用Application作为参数和用NULL作为参数有什么不同呢?
还有,就是在线程里使用动态创建的TTimer究竟有什么不安全的地方呢?
...全文
77 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
yhmeier 2008-07-31
  • 打赏
  • 举报
回复
十分感谢!
unsigned(僵哥)实在太厉害了!
僵哥 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 yhmeier 的回复:]
十分感谢!!
再请教一个问题,如果程序里有多个线程,在其中一个线程里动态创建了TTimer,那会不会因为其它线程的执行而使定时的时间不准确呢?
[/Quote]
理论上来讲,线程与线程之间是相互独立的,但是如果是系统处于相当繁忙的状态,特别是一些高优级的进程进执行作业的时候,Timer是有可能会受到影响的。TTimer使用的是WM_TIMER消息,这个本身并不保证有多高的精确度。如果想要使用高精确度的定时器,可以使用多媒体定时器。
unit PreciseTimerUnit;

interface

uses
Windows,MMSystem,UnitManagedObject;

type
TTimerEvent=procedure (Sender:TObject) of Object;

TPreciseTimer=class(TManagedObject)
strict private
FPurifierTimer:UINT;
FOnTimerEvent:TTimerEvent;
FInterval: UINT;
FResolution: UINT;
private
procedure RaiseTimerEvent;
public
property OnTimer:TTimerEvent read FOnTimerEvent write FOnTimerEvent;
property Interval: UINT read FInterval;
public
Constructor Create;overload;
Constructor Create(AInterval: UINT);overload;
Destructor Destroy;override;
end;
const
TIME_KILL_SYNCHRONOUS:UINT=$0100;
var
WinVersion:DWORD;
implementation

function ByteSwap(value:DWORD):DWORD; assembler;
asm
BSWAP eax
end;

procedure TPreciseTimer.RaiseTimerEvent;
begin
if Assigned(FOnTimerEvent) then
FOnTimerEvent(Self);
end;

procedure PurifierTimerProc(uTimerID, uMessage: UINT;
dwUser, dw1, dw2: DWORD) stdcall;
var
pTimer: TPreciseTimer;
begin

pTimer := TPreciseTimer(dwUser);
if pTimer.Attach <> pTimer then
Exit;
try
pTimer.RaiseTimerEvent;
finally
pTimer.Free;
end;
end;

constructor TPreciseTimer.Create;
begin
Create(1000);
end;

constructor TPreciseTimer.Create(AInterval: UINT);
var
fuEvent:UINT;
tc: TIMECAPS;
begin
Inherited Create;
FInterval := AInterval;
FOnTimerEvent := Nil;
if timeGetDevCaps(@tc, SizeOf(TIMECAPS)) <> TIMERR_NOERROR then Exit;
FResolution := tc.wPeriodMin;
if timeBeginPeriod(FResolution) <> TIMERR_NOERROR then Exit;;

fuEvent:=TIME_PERIODIC;
if(HiWord(byteswap( WinVersion))>=$501) then//WinXP or Later
fuEvent:=fuEvent or TIME_KILL_SYNCHRONOUS;

FPurifierTimer:=timeSetEvent(Interval,
0,
PurifierTimerProc,
DWORD_PTR(self),
fuEvent);
if(0=FPurifierTimer) then
timeEndPeriod(FResolution);
end;

destructor TPreciseTimer.Destroy;
begin
if(0<>FPurifierTimer) then
begin
timeKillEvent(FPurifierTimer);
timeEndPeriod(FResolution);
FPurifierTimer:=0;
Sleep(15);
end;
end;

initialization
WinVersion:=GetVersion;
finalization

end.

UnitManagedObject中主要定义的是一个TManagedObject,用于管理引用计数,这个无关紧要,上面就是一个多媒体定时器类的代码
yhmeier 2008-07-31
  • 打赏
  • 举报
回复
十分感谢!!
再请教一个问题,如果程序里有多个线程,在其中一个线程里动态创建了TTimer,那会不会因为其它线程的执行而使定时的时间不准确呢?
僵哥 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 whomin 的回复:]
我觉得并无不同啊——
线程动态创建的TTimer不安全么?真的不安全么?严重怀疑
[/Quote]
没说线程创建就不安全,先看清楚。
whomin 2008-07-31
  • 打赏
  • 举报
回复
僵哥说得有道理,这个是很容易造成访问冲突的异常。
不过我每次释放Application前都是先确保所有线程释放后(先通知线程,再用WaitForMultiObjects等吧),最后进行应用的释放的,这种情况下就没问题。
whomin 2008-07-31
  • 打赏
  • 举报
回复
我觉得并无不同啊——
线程动态创建的TTimer不安全么?真的不安全么?严重怀疑
僵哥 2008-07-31
  • 打赏
  • 举报
回复
如果以Application作为参数,当Application释放的时候,会将TTimer一并释放,此时在线程当中就会导致TTimer指针操作的不可控性,很有可能会因为Application释放Components列表的时候,线程仍然在执行,从而当TTimer被释放掉之后,线程操作到的是一个野指针。

604

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder VCL组件使用和开发
社区管理员
  • VCL组件使用和开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧