德尔福:没有冻结和处理消息的睡眠

时间:2015-06-24 12:22:58

标签: windows delphi delphi-7 delphi-2007

我需要一种暂停函数执行几秒钟的方法。我知道我可以使用睡眠方法来做到这一点,但这种方法会冻结'应用程序执行时。我也知道我可以使用类似下面的代码来避免冻结:

// sleeps for 5 seconds without freezing 
for i := 1 to 5 do
    begin
    sleep(1000);
    application.processmessages;
    end;

这种方法存在两个问题:一个是冻结仍然每一秒钟发生一次,第二个问题是调用“应用程序。进程消息”。每一秒。我的应用程序是CPU密集型的,每个进程消息调用做了很多不必要的工作,使用不必要的CPU功率;我只想暂停工作流程,仅此而已。

我真正需要的是像TTimer一样暂停执行的方法,在下面的示例中:

   // sleeps for 5 seconds
   mytimer.interval := 5000;
   mytimer.enabled := true;
   // wait the timer executes
   // then continue the flow
   // running myfunction
   myfunction;

这种方法的问题是' myfunction'不会等待mytimer,它会在mytimer启用后立即运行。

是否有另一种方法可以实现我想要的暂停?

提前致谢。

4 个答案:

答案 0 :(得分:13)

正如大卫所说,最佳选项是将工作转移到一个单独的线程中,并完全阻止主线程。但是,如果你必须阻止主线程,那么至少你应该只在有等待处理的消息时调用ProcessMessages(),让线程在剩下的时间内休眠。您可以使用MsgWaitForMultipleObjects()来处理该问题,例如:

var
  Start, Elapsed: DWORD;

// sleep for 5 seconds without freezing 
Start := GetTickCount;
Elapsed := 0;
repeat
  // (WAIT_OBJECT_0+nCount) is returned when a message is in the queue.
  // WAIT_TIMEOUT is returned when the timeout elapses.
  if MsgWaitForMultipleObjects(0, Pointer(nil)^, FALSE, 5000-Elapsed, QS_ALLINPUT) <> WAIT_OBJECT_0 then Break;
  Application.ProcessMessages;
  Elapsed := GetTickCount - Start;
until Elapsed >= 5000;

可替换地:

var
  Ret: DWORD;
  WaitTime: TLargeInteger;
  Timer: THandle;

// sleep for 5 seconds without freezing 
Timer := CreateWaitableTimer(nil, TRUE, nil);
WaitTime := -50000000; // 5 seconds
SetWaitableTimer(Timer, WaitTime, 0, nil, nil, FALSE);
repeat
  // (WAIT_OBJECT_0+0) is returned when the timer is signaled.
  // (WAIT_OBJECT_0+1) is returned when a message is in the queue.
  Ret := MsgWaitForMultipleObjects(1, Timer, FALSE, INFINITE, QS_ALLINPUT);
  if Ret <> (WAIT_OBJECT_0+1) then Break;
  Application.ProcessMessages;
until False;
if Ret <> WAIT_OBJECT_0 then
  CancelWaitableTimer(Timer);
CloseHandle(Timer);

答案 1 :(得分:8)

将需要暂停的任务移动到单独的线程中,以便它不会干扰UI。

答案 2 :(得分:1)

令人怀疑的是,Application.ProcessMessages真的会消耗太多的处理器时间。您可以尝试存储开始等待的时刻,然后开始重复Application.ProcessMessages直到......;圈检查存储时间和当前时间之间的时间跨度。

答案 3 :(得分:0)

如果使用计时器没有问题,可以执行以下操作:

(ouside the timer-event:)
mytimer.interval := 5000;
mytimer.tag:=0;
mytimer.enabled := true;

(inside the timer-event:)
mytimer.tag:=mytimer.tag+1;
if mytimer.tag=2 then begin
  mytimer.enabled:=false;
  myfunction;
end;