windows win32 服务中的计时器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/224043/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:30:08  来源:igfitidea点击:

Timer in a win32 service

c++windowswinapiwindows-services

提问by dennisV

Can someone please point me to the easiest way to have a timer in a Win32 service?

有人可以指点我在 Win32 服务中使用计时器的最简单方法吗?

I suppose I could create a dummy window for this purpose or have a second thread do tick counts, but what's best? Is there a more elegant way?

我想我可以为此创建一个虚拟窗口,或者让第二个线程进行滴答计数,但什么是最好的?有没有更优雅的方式?

Thanks in advance.

提前致谢。

回答by denis phillips

You can use Timer Queues (http://msdn.microsoft.com/en-us/library/ms686796.aspx). They don't require an HWND.

您可以使用计时器队列 ( http://msdn.microsoft.com/en-us/library/ms686796.aspx)。他们不需要 HWND。

回答by Adam Mitz

Instead of using UI timers (even though you can use the NULL window handle as shown by Mr. 1800-INFO) you can use kernel waitable timer objects. See CreateWaitableTimerin the API docs. These can then be waited-on using WaitForSingleObject or WaitForMultipleObjects, etc, which is especially useful if that's already how your service waits for external events.

除了使用 UI 计时器(即使您可以使用 1800-INFO 先生所示的 NULL 窗口句柄),您还可以使用内核可等待计时器对象。请参阅API 文档中的CreateWaitableTimer。然后可以使用 WaitForSingleObject 或 WaitForMultipleObjects 等来等待这些,如果您的服务已经这样等待外部事件,这将特别有用。

If it's not clear from that first link, the SetWaitableTimer function can associate a completion routine (user callback) with the timer. Remember to use the ...Ex versions of WaitForMultipleObjects (etc.) so that the thread is in an "alertable" state.

如果第一个链接不清楚,SetWaitableTimer 函数可以将完成例程(用户回调)与计时器相关联。请记住使用 WaitForMultipleObjects(等)的 ...Ex 版本,以便线程处于“警报”状态。

回答by 1800 INFORMATION

You can send your main thread WM_TIMER messages. The lParam for the message is the address of a callback function, or you can leave it NULL and handle it yourself in your message pump.

您可以发送主线程 WM_TIMER 消息。消息的 lParam 是回调函数的地址,或者您可以将其保留为 NULL 并在您的消息泵中自行处理。

In this example, we are sending the timer to the thread message pump, there is no requirement to have a window associated with the timer.

在这个例子中,我们将定时器发送到线程消息泵,不需要有一个与定时器关联的窗口。

UINT timer;

VOID CALLBACK Timer(HWND hwnd,
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime
)
{
  KillTimer(0, timer);
}

timer=SetTimer(0, // window handle
    0, // id of the timer message, leave 0 in this case
    10000, // millis
    Timer // callback
  );

// pump messages
while (GetMessage) etc...

The Timer callback will be called by DispatchMessage. This question reminded me of the recent ONT.

DispatchMessage 将调用 Timer 回调。这个问题让我想起了最近的ONT

回答by David L Morris

In one of your comments you said that "...the service is processing stuff in other threads, I just need to check the status of a few files every second."

在您的评论之一中,您说“...该服务正在其他线程中处理内容,我只需要每秒检查几个文件的状态。”

Polling is not an optimal way of checking file status, and will adversely affect system performance. While there are (sometimes) problems doing this over networks, you should check out http://msdn.microsoft.com/en-us/library/aa364417(VS.85).aspxor http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspxfor how to do it and http://blogs.msdn.com/oldnewthing/archive/2006/01/24/516808.aspxfor why you should.

轮询不是检查文件状态的最佳方式,并且会对系统性能产生不利影响。虽然通过网络执行此操作(有时)存在问题,但您应该查看http://msdn.microsoft.com/en-us/library/aa364417(VS.85).aspxhttp://msdn.microsoft.com /en-us/library/aa365261(VS.85).aspx了解如何做,以及http://blogs.msdn.com/oldnewthing/archive/2006/01/24/516808.aspx了解为什么你应该这样做。

回答by Steve

You can use SetTimer to set the timer, then catch the WM_TIMER message in your message loop.

您可以使用 SetTimer 设置计时器,然后在消息循环中捕获 WM_TIMER 消息。

Example:

例子:

// Set a timer to expire in 10 seconds

// 设置一个定时器在 10 秒后到期

SetTimer(hwnd,IDT_TIMER1, 10000,(TIMERPROC) NULL);

SetTimer(hwnd,IDT_TIMER1, 10000,(TIMERPROC) NULL);

... then in message loop:

...然后在消息循环中:

switch (wParam)

开关(wParam)

{ 

    case IDT_TIMER1: 

        // Boom goes the dynamite

You can also decleare a function of type TIMERPROC and have that be called when the timer expires, if you don't want to do the message loop handling.

如果您不想进行消息循环处理,您还可以取消清除 TIMERPROC 类型的函数,并在计时器到期时调用该函数。

回答by John Dyer

Are you just trying to "wake up" every now and then to do some work? You can always use Sleep().

你只是想不时“醒来”做一些工作吗?您始终可以使用 Sleep()。

Additionally, I typically have a thread that is in a while(1 == 1) loop with a sleep inside. There I can check for the shutdown request and other misc housekeeping. You could use that system to tickle an event or mutex for the worker thread in the app.

此外,我通常有一个处于 while(1 == 1) 循环中的线程,里面有一个 sleep 。在那里我可以检查关闭请求和其他杂项管理。您可以使用该系统为应用程序中的工作线程触发事件或互斥锁。