除非收到消息,否则有办法入睡吗?

Mas*_*ler 3 windows delphi service winapi

我正在使用一个主循环看起来像这样的服务:

while (fServer.ServerState = ssStarted) and (Self.Terminated = false) do
begin
  Self.ServiceThread.ProcessRequests(false);
  ProcessFiles;
  Sleep(3000);      
end;
Run Code Online (Sandbox Code Playgroud)

ProcessRequests很像Application.ProcessMessages.我无法传递true给它,因为如果我这样做,它会阻塞,直到从Windows收到消息,并且ProcessFiles将无法运行,并且它必须不断运行.Sleep可以降低CPU使用率.

这工作正常,直到我尝试从Windows的服务管理列表关闭服务.当我点击Stop时,它会发送一条消息并希望几乎立即得到响应,如果它在Sleep命令的中间,Windows会给我一个错误,表明该服务没有响应Stop命令.

所以我需要说的是"睡觉3000或直到你收到消息,以先到者为准".我确定有一个API,但我不确定它是什么.有人知道吗?

Jer*_*ers 11

这种东西很难做到,所以我通常从MSDN的API文档开始.

WaitForSingleObject的机制的文档特别指示,以MsgWaitForMultipleObjects这些种情况:

调用等待函数和直接或间接创建窗口的代码时要小心.如果一个线程创建了任何窗口,它必须处理消息.消息广播被发送到系统中的所有窗口.使用没有超时间隔的等待函数的线程可能会导致系统死锁.间接创建窗口的两个代码示例是DDE和 CoInitialize函数.因此,如果您有一个创建窗口的线程,请使用MsgWaitForMultipleObjectsMsgWaitForMultipleObjectsEx,而不是WaitForSingleObject.

MsgWaitForMultipleObjects中,您有一个dwWakeMask参数指定要返回的排队消息,以及一个描述您可以使用的掩码的表.

由于Warren P的评论而编辑:

如果您的主循环可以通过ReadFileEx,WriteFileExQueueUserAPC继续,那么您可以使用SleepEx.

--jeroen


Rem*_*eau 8

MsgWaitForMultipleObjects() is the way to go, ie:

while (fServer.ServerState = ssStarted) and (not Self.Terminated) do 
begin 
  ProcessFiles; 
  if MsgWaitForMultipleObjects(0, nil, FALSE, 3000, QS_ALLINPUT) = WAIT_OBJECT_0 then
    Self.ServiceThread.ProcessRequests(false); 
end;
Run Code Online (Sandbox Code Playgroud)

If you want to call ProcessFiles() at 3 second intervals regardless of any messages arriving, then you can use a waitable timer for that, ie:

var
  iDue: TLargeInteger;
  hTimer: array[0..0] of THandle;
begin
  iDue := -30000000; // 3 second relative interval, specified in nanoseconds
  hTimer[0] := CreateWaitableTimer(nil, False, nil);
  SetWaitableTimer(hTimer[0], iDue, 0, nil, nil, False);
  while (fServer.ServerState = ssStarted) and (not Self.Terminated) do 
  begin 
    // using a timeout interval so the loop conditions can still be checked periodically
    case MsgWaitForMultipleObjects(1, hTimer, False, 1000, QS_ALLINPUT) of
      WAIT_OBJECT_0:
      begin
        ProcessFiles;
        SetWaitableTimer(hTimer[0], iDue, 0, nil, nil, False);
      end;
      WAIT_OBJECT_0+1: Self.ServiceThread.ProcessRequests(false);
    end;
  end;
  CancelWaitableTimer(hTimer[0]);
  CloseHandle(hTimer[0]);
end;
Run Code Online (Sandbox Code Playgroud)