问题描述
- Delphi的计时器问题:会不会造成同时操作全局变量的冲突
-
假如有一个操作是增加一个全局变量的值,但是还有一个计时器也用于定时增加该全局变量的值,那么假如在执行前一个操作的时候同时计时器也正好触发执行,这样会不会有冲突。以下面的代码为例,假如在你点击按钮的时候同时计时器被触发会怎么样?
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) btn1: TButton; tmr1: TTimer; procedure btn1Click(Sender: TObject); procedure tmr1Timer(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; i: Integer; implementation {$R *.dfm} procedure TForm1.btn1Click(Sender: TObject); begin Inc(i); btn1.Caption:= IntToStr(i) end; procedure TForm1.tmr1Timer(Sender: TObject); begin Inc(i); btn1.Caption:= IntToStr(i); end; end.
解决方案
Timer是一种最少计数为毫秒(1/1000秒)的计时器,它可以1毫秒,执行一次事件。
Timer基本上是两种用法:
一、定时启动,代码完成后,终止。此类问题通常情况下,不会有任何问题。
二、每天定时启动代码,完成每天的记录功能。
此类操作要注意:
1、TTimer事件中,只执行全局变量,对VCL的操作,通发送过消息。
2、不宜在TTimer事件中,执行有形的控件,特别是涉及到读写磁盘或画面的代码,代码执行时会滞留时间,会造成TTimer计量,与代码执行不同步问题。
3、在事件中调用外部程序,特别是程序中涉及控件的写画,程序会返回到事件的起步代码,因而出现“频闪”现象。即一次事件中,循环执行数十次。
procedure TForm1.tmr1Timer(Sender: TObject);
begin
Inc(i);
btn1.Caption:= IntToStr(i);
end;
虽然可以执行,但不完美。应该通过发送消息,来显示btn1.Caption。 建议改成:
procedure TForm1.Timer1Timer(Sender: TObject);
var s:string;
begin
i:=i+1;
S:=IntTostr(i);
SendMessage(Button1.handle, WM_SETTEXT, 0, LPARAM(S));
application.ProcessMessages;
end;
解决方案二:
没有问题,按钮和计时器其实在一个消息队列中,是逐个处理的。
解决方案三:
计时器是消息队列中,不会同时的!不存在并发的问题,如果是线程的话,就需要处理同步