Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

Lazarus IDE and 组件 下载地址版权申明
查看: 3546|回复: 6

小议Timer重入问题

[复制链接]

该用户从未签到

发表于 2013-4-17 09:05:12 | 显示全部楼层 |阅读模式
小议Timer重入问题
在Lazarus中 ,TTimer是一个定时器,他封装了API,将按一定时间自动执行 ontimer这个句柄指向的回调函数。
那么这个回调是否就是一个线程呢?
很明显不是一个单独的线程,下面这个例子就可以说明,主要代码:
Var t:integer;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  inc(t);
  memo1.lines.add((sender as ttimer).name + ':' + inttostr(t));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  t :=0;
  memo1.lines.add('formcreate:' + inttostr(t));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
   timer1.Enabled := false;
   timer2.enabled := false;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
begin
  inc(t);
  memo1.lines.add((sender as ttimer).name  + ':' + inttostr(t));
end;
就是两个定时器,定时修改全局变量t,并且显示是哪个修改的,当前值是多少。并且
我们在任务管理器里面查看,发现线程数一直都是1.
那么这个回调函数相当于什么呢?
还是主线程中的一块普通代码,和button1click 没有什么大的区别。否则如果是多个线程,就需要互斥访问变量t了,我们并没有加入这样的代码。
那么小的区别在哪里?
Ttimer的定时回调函数,是由系统时钟发起的消息,执行的。也就是说,如果我们在里面执行显示模态窗口等常规情况下会暂停主线程的方法会失效,这是其一。
第2点就是,无论这个回调函数有没有执行完毕,只要下一个时间到,回调函数将会重头开始执行。下面这个例子就能很好的表达这个问题。
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  inc(t);
  application.MessageBox('','', 0);
  inc(t);
  memo1.lines.add((sender as ttimer).name + ':' + inttostr(t));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  t :=0;
  memo1.lines.add('formcreate:' + inttostr(t));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
   timer1.Enabled := false;
   timer2.enabled := false;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
begin
  inc(t);
  memo1.lines.add((sender as ttimer).name  + ':' + inttostr(t));
end;
注意 application.MessageBox('','', 0); 这句, 明明我们已经将主线程用显示窗口暂停了的样子,但是调试器却显示timer时间到,代码又从头开始执行了,导致application对象试图反复创建模态窗口,这是不正确的,也只有timer能够做到,没有关闭模态窗口,又创建并显示模态窗口,但是会报错。
file:///C:/WINDOWS/TEMP/ksohtml/wps_clip_image1.png
那么如何解决此类问题。
在此回调函数的开始第1句,使用 (sender as ttimer).enabled := false;
再在需要的地方进行 enabled :=true;
如果是多个timer ,也可以将所有timer 禁止,在需要的地方恢复。
根据业务逻辑。
By steven
Fpccn.com
2013年4月

回复

使用道具 举报

该用户从未签到

发表于 2013-4-19 15:17:40 | 显示全部楼层
可以将Timer理解为硬件定时器。

处理的方法:

      1、如steven的,直接对Timer进行使能控制。

      2、不对Timer使能控制,根据业务代码的长短,调整Timer的定时值,从而实现连续性。

      3、不对Timer使能控制,根据设定的Timer定时值,调整业务代码,使得在业务在定时时间内完成,也可以实现连续性。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2013-5-6 15:18:43 | 显示全部楼层
如果实时性要求比较高,用定时时间到后开辟新线程的方法处理比较好,线程互斥处理业务,业务处理完毕,线程销毁。使能控制,遇到短时间大流量操作,有点力不从心
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2013-5-9 11:26:47 | 显示全部楼层
挺不错的教程!
加油!加油!
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2013-5-9 21:10:47 | 显示全部楼层
不管说的技术含量高与低,用于表达总是值得称赞。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2013-9-2 11:45:09 | 显示全部楼层
非常不错,谢谢。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2014-2-7 22:04:55 | 显示全部楼层
嗯,的确是如此的。
回复 支持 反对

使用道具 举报

*滑块验证:

本版积分规则

QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

GMT+8, 2025-5-2 20:56 , Processed in 0.032538 second(s), 10 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表