c++ win 定时器 WaitableTimer
参考 https://www.cnblogs.com/lisuyun/articles/5581435.html
参考 https://blog.csdn.net/EasyVCR/article/details/6856473
目前,Windows下的定时器编程主要有三种方式。
1)SetTimer定时器是利用Windows窗口消息WM_TIMER来实现的。使用方法非常简单,SetTimer创建定时器,KillTimer销毁定时器。使用条件是调用线程必须要有窗口消息队列message queue,因此如果是工作线程就无法使用这种方法。
2)WaitableTimer定时器,其实应该算是一种线程同步对象,CreateWaitableTimer创建定时器对象,SetWaitableTimer设置定时器回调函数,CLoseHandle销毁定时器。WaitableTimer可以跨线程、进程使用,只要知道定时器对象名字(创建定时器时设置)就可以控制该定时器对象了。WaitableTimer定时器的回调函数实际上是一个APC(Asynchronous Procedure Calls)异步过程调用函数。
关于APC方面的知识可参考“谈谈对APC的一点理解”一文http://blog.csdn.net/wwwwly/archive/2009/07/10/4337907.aspx
3)TimerQueueTimer定时器,应该算迄今为止Windows系统最强大的定时器了。他可以支持多种工作模式,而且定时精度也是最高的。
使用时,首先要调用CreateTimerQueue创建一个定时器队列,然后用
CreateTimerQueueTimer来创建一个TimerQueueTimer定时器,
WT_EXECUTEDEFAULT,默认设置,回调函数将进入一个非I/O工作线程队列
WT_EXECUTEINTIMERTHREAD,回调函数作为APC,在定时器线程中被调用,被调用的条件是线程进入可警告等待状态alertable wait status。仅适用于短时任务,否则可能会影响队列中的其他定时器。
WT_EXECUTEINIOTHREAD,回调函数进入一个I/O工作线程队列,
请注意,大多数定时器都需要调用线程进入可警告等待状态alertable wait status,并不是随随便便就能发生定时调用的。一个线程是否进入可警告等待状态可参见微软的说明http://msdn.microsoft.com/en-us/library/ms686307.aspx
A thread goes into an alertable wait state by calling either SleepEx, MsgWaitForMultipleObjectsEx, WaitForSingleObjectEx, or WaitForMultipleObjectsEx, with the function's bAlertable parameter set to TRUE.
所以希望定时器不受这种可警告等待状态的影响,最好是用TimerQueue来完成。
相比之下, WaitableTimer 传递参数,传递一个结构体,就可以, 方便定时器 控制和关闭
此处记录下, WaitableTimer 的简单使用
#include <Windows.h> #include <stdio.h> struct Devicetext { unsigned int status;//设备状态 time_t t;//记录最近一次通讯时间值 //如果长时间未通讯,则,更改状态为下线 string pos;//记录在哪一个服务器上 string deviceid;//设备id HANDLE hTimer; }; VOID APIENTRY TimerAPCRoutine( PVOID pvArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue) { cout << "high:" << dwTimerHighValue << " low" << dwTimerLowValue << endl; Devicetext* device = (Devicetext*)pvArgToCompletionRoutine; cout << "pvArgToCompletionRoutine:" << device->deviceid << endl << endl; } int main() { HANDLE hTimer = CreateWaitableTimer(NULL, FALSE, NULL); LARGE_INTEGER li; li.QuadPart = 0; Devicetext device; device.deviceid = "6800000000000001"; if (!SetWaitableTimer(hTimer, &li, 1000, TimerAPCRoutine,&device, FALSE)) { CloseHandle(hTimer); return 0; } device.hTimer = hTimer; while (1) { SleepEx(5000, TRUE);cout << "main sleep" << endl; }
//查看 handle 是否合法,合法 GetHandleInformation 返回1,不合法返回0
DWORD dwFlags1;
cout << "main GetHandleInformation:" << GetHandleInformation(hTimer, &dwFlags1) << endl << endl;
CloseHandle(hTimer);
cout << "main GetHandleInformation:" << GetHandleInformation(hTimer, &dwFlags1) << endl << endl;
cout << "main device->hTimer:" << device.hTimer << endl << endl;
return 0; }
//
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构