问题来源于:
http://www.cnblogs.com/del/archive/2009/02/16/1391192.html
其中有一段代码:
procedure TForm1.Button5Click(Sender: TObject);
begin ShowMessage('TEvent 类没有提供这个功能'); {我试过用 PulseEvent(MyEvent.Handle) 也不行} end;
作者只是说TEvent类没有这个功能或者直接使用PulseEvent也没有效果,但没有给出其他更多的解释。
在经过我一晚上艰苦卓绝(熬瞎眼)的努力下,现在终于把这个问题搞明白了。
首先,这个问题既不算Bug也不算问题,应该属于使用上和理论上的误区导致的。
简单点儿说,PulseEvent这个脉动事件实际上实在是太快了,它的状态转换时间远远少于TEvent.WaitFor的执行时间。也就是说在TEvent.WaitFor根本就没有响应过来(没明白是什么状况时)这个脉动事件已经结束了!!!!是不是有点拗口?好吧,直接上代码:
while not Terminated do
begin
if WaitForSingleObject(FEvent.Handle, INFINITE) = WAIT_OBJECT_0 then
//if FEvent.WaitFor(INFINITE) = wrSignaled then
begin
Synchronize(DoView);
Sleep(1);
end;
end;
注意:上面的FEvent.WaitFor(INFINITE)语句在PulseEvent时永远不会触发,但是换成WindowsAPI:
WaitForSingleObject(FEvent.Handle, INFINITE) = WAIT_OBJECT_0
以API方式执行时却完全没有问题。
结论:只要在线程中使用WindowsApi方式进行事件等待即可解决问题。具体的调用方式就是你想怎么PulseEvent就怎么PulseEvent,完全不影响线程的正常运行。
一旦搞清楚了原理,那么很多事情就很好玩了,比如:
1.跨平台执行,很简单:
procedure TMnEvent.PulseEvent;
begin
{$IFDEF MSWINDOWS}
Windows.PulseEvent(Handle);
{$ELSE}
FEvent.SetEvent;
FEvent.ResetEvent;
{$ENDIF}
end;
唯一一点需要注意的是:这种使用SetEvent和ResetEvent的方式绝对没有操作系统核心处理的精确,也就是说很难控制只执行一次。当然,如果你的系统要求不高,也可以在Windows上使用这种方式来执行,这种权衡就全部交给你自己控制吧。
2.将TEvent.WaitFor事件改为纯汇编方式执行???这个我不敢确认是否能够成功,也没有进行实验,因此只能交给有兴趣的同学去继续测试吧。