我需要一种将函数的​​执行暂停几秒钟的方法。我知道我可以使用sleep方法来执行此操作,但是此方法会在执行过程中“卡住”应用程序。我也知道我可以使用类似下面的代码来避免卡住:

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

这种方法有两个问题:一个是事实仍然是每秒卡住一次,第二个问题是每秒调用“application.processmessages”。我的应用程序占用大量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之后立即运行。

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

提前致谢。

最佳答案

正如David所说,最好的选择是将工作移到一个单独的线程中,并完全停止阻塞主线程。但是,如果必须阻塞主线程,则至少应仅在确实有等待处理的消息时才调用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);

10-08 01:16