对于临界区,我常常在多线程编程中使用,来保护关键代码段,像下面的代码:
type TClient=class private FLock: TRTLCriticalSection; public procedure Lock; procedure UnLock; constructor Create; destructor Destroy; override; end; implementation procedure TClient.Lock; begin EnterCriticalSection(FLock); end; procedure TClient.UnLock; begin LeaveCriticalSection(FLock); end; constructor TClient.Create; begin InitializeCriticalSection(FLock); inherited Create; end; destructor TClientSocket.Destroy; begin inherited; DeleteCriticalSection(FLock); end;
但今天在使用Indy控件编程的时候,发现Lock函数并没有阻塞住,经过研究,发现:
只要程序界面加了 TIdAntiFreeze 控件,Timer1的事件过程就会重入。
事件的重入很好理解,因为Indy的TIdAntiFreeze控件,就是在Indy在执行阻塞操作时,在后台不断调用 Application.ProcessMessage,来处理消息,防止界面卡死。
但Lock并没有锁住关键代码段,即,代码在EnterCriticalSection(FLock)处并没有阻塞(已经执行了一次Lock,还没有执行UnLock的时候),经我反复测试发现,原来,
临界区锁,只对不同线程才保护关键代码段,同一线程的话,则根本不会锁的。
所以,我们在Delphi中编程的时候,要慎用 Application.ProcessMessage。
在Timer事件中,为防止重入,可以先禁用Timer,等事件函数执行完成后,在启用Timer,如:
Timer2.Enabled := False; try //你的代码 finally Timer2.Enabled := True; end;
(Delphi编程感悟:wlmbz 20130701)