Windows高精度微秒级(并发)定时器实现
2017-04-10 21:35
288 查看
自从上次封装微秒延时函数后,利用空闲时间试着封装一个微秒定时器(类似MFC定时器形式)使用起来效果还不错。
关于定时器的几点介绍:
1.设计采用了自动释放定时器节点方式(增加虚析构函数在内部做相关释放判断,即使用完不释放节点也没关系);
2.设计采用了双向链表方式做定时器节点(为了方便起见,没有采用环形双向链表);
3.增加了第三参数为回调函数(采用MFC风格,如果第三个参数不为空,超时后调用回调函数,否则调用默认函数);
4.设计采用了并行方式(可以同时启动多个ID不相同的定时器,并且每个定时器之间没有影响);
5.释放采用了先退出定时器线程,后删除节点风格(防止数据异常造成崩溃)。
函数定义如下:
代码实现如下:
使用方式:
关于微秒级延时函数详细介绍参考:http://blog.csdn.net/a29562268/article/details/68955533!
关于定时器的几点介绍:
1.设计采用了自动释放定时器节点方式(增加虚析构函数在内部做相关释放判断,即使用完不释放节点也没关系);
2.设计采用了双向链表方式做定时器节点(为了方便起见,没有采用环形双向链表);
3.增加了第三参数为回调函数(采用MFC风格,如果第三个参数不为空,超时后调用回调函数,否则调用默认函数);
4.设计采用了并行方式(可以同时启动多个ID不相同的定时器,并且每个定时器之间没有影响);
5.释放采用了先退出定时器线程,后删除节点风格(防止数据异常造成崩溃)。
函数定义如下:
//参数一 定时器ID号,参数二 定时时间(微秒),参数三 回调函数(不需要设置NULL或者不写) int TimeRun(int id,int outtime,void (CALLBACK* lpfnTimer)(/*HWND, UINT, UINT_PTR, DWORD*/) = NULL);//定时器启动函数 //参数一 定时器ID号 void TestKillTimer(int id);//定时器销毁函数 (可以不使用) void CALLBACK Test123();//测试写的回调函数 函数名称及参数可以自己定 与定时器内以及定时器结构体的回调函数配套 //第一个参数 定时器ID号(ID号用于多个定时器之间的判断) void TestTime(int id);//测试用的普通定时器调用函数 想启动的函数写在这个函数内 DWORD WINAPI TimerRunThread(LPVOID _this);//定时器线程函数 typedef struct timest//定时器数据保存结构体 { int id;//ID号 int outtime;//超时时间 volatile int beginRun;//运行状态 void (CALLBACK* lpfnTimer)(/*HWND, UINT, UINT_PTR, DWORD*/);//回调函数 timest *prev,*next;//双向链表指针 }*ptimest; typedef struct Testtimest//定时器执行结构体 { ptimest ptime,ptimehead;//定时器运行节点以及头节点 Testtimest() { ptime = 0; ptimehead = 0; } virtual ~Testtimest()//析构函数内部封装了定时器对象退出后的检查及释放 { while (0 != ptimehead) { ptimest deletime; deletime = ptimehead->next; if (1 == ptimehead->beginRun)//如果定时线程还在执行 ,先退出线程再删除 { ptimehead->beginRun = 0; UsSleep(ptimehead->outtime * 2);//删除线程节点前要留出当前定时器的2倍睡眠时间 } delete ptimehead; ptimehead = deletime; } } }; Testtimest testtime;
代码实现如下:
int TimeRun(int id,int outtime,void (CALLBACK* lpfnTimer)(/*HWND, UINT, UINT_PTR, DWORD*/))//定时器启动实现 采用了可以多次重复创建并且删除的安全方式 { if (0 > id || 0 >= outtime) { return -1; } testtime.ptime = testtime.ptimehead;//为方便多次删除后继续用,每次先获取首节点 if (0 != testtime.ptime)//如果头节点不为空,判断当前新增定时器ID是否与之前增加ID重复 { while (id != testtime.ptime->id && 0 != testtime.ptime->next) testtime.ptime = testtime.ptime->next; if (id == testtime.ptime->id)//如果启动的定时器Id与之前的重复 则不启动 { return -1; } } if (0 == testtime.ptime) { testtime.ptime = new timest; testtime.ptime->next = 0; testtime.ptime->prev = 0; testtime.ptimehead = testtime.ptime; } else { while (0 != testtime.ptime->next) testtime.ptime = testtime.ptime->next; testtime.ptime->next = new timest; testtime.ptime->next->next = 0; testtime.ptime->next->prev = testtime.ptime; } while (0 != testtime.ptime->next) testtime.ptime = testtime.ptime->next; testtime.ptime->id = id;//id testtime.ptime->beginRun = 1;//启动状态 testtime.ptime->outtime = outtime;//超时时间 testtime.ptime->lpfnTimer = lpfnTimer;//回调函数 HANDLE handle = CreateThread(NULL,0,TimerRunThread,testtime.ptime,0,NULL); CloseHandle(handle);//为了C程序也能运行采用了API线程,并且句柄没实际用处就直接释放掉 return 0; } void CALLBACK Test123()//测试回调函数实现 { int a; a = 2; } DWORD WINAPI TimerRunThread(LPVOID _this)//定时器线程函数实现 { ptimest Runject = (/*decltype(_this)*/ptimest)_this;//本来想用获取类型方式来直接获取传入的类型,后来想到了在线程函数中类型是void*所以只能手动写入传入的参数类型 while (1 == Runject->beginRun)//定时器状态为1执行,0时退出线程函数,删除定时器节点 { UsSleep(Runject->outtime); if (0 != Runject->lpfnTimer)//如果回调函数不为空调用回调函数 { Runject->lpfnTimer(); } else { TestTime(Runject->id);//根据ID号进行调用普通定时器启动函数 } } return 0; } void TestTime(int id)//测试 定时器调用函数实现 { int a = 0; if (1 == id) { a = 1; } if (2 == id) { a = 2; } if (3 == id) { a = 3; } } void TestKillTimer(int id)//定时器销毁函数实现 { ptimest deletime = testtime.ptimehead; ptimest next,prev; if (id == deletime->id)//首节点 { next = testtime.ptimehead->next; deletime->beginRun = 0; UsSleep(deletime->outtime * 2);//为了可以退出定时器线程并且安全删除定时器节点采用了2倍超时时间 delete deletime; deletime = 0; testtime.ptimehead = next; if (0 != next) { next->prev = 0; } return ; } while (id != deletime->id && 0 != deletime) deletime = deletime->next; if (0 == deletime)//没有找到Id { return ; } prev = deletime->prev; next = deletime->next; deletime->beginRun = 0; UsSleep(deletime->outtime * 2); delete deletime; deletime = 0; prev->next = next; if (0 != next) { next->prev = prev; } } int UsSleep(int us)//微秒延时函数实现 { LARGE_INTEGER fre; if (QueryPerformanceFrequency(&fre)) { LARGE_INTEGER run,priv,curr,res; run.QuadPart = fre.QuadPart * us / 1000000; QueryPerformanceCounter(&priv); do { QueryPerformanceCounter(&curr); } while (curr.QuadPart - priv.QuadPart < run.QuadPart); curr.QuadPart -= priv.QuadPart; int nres = (curr.QuadPart * 1000000 / fre.QuadPart); return nres; } return -1;// }
使用方式:
TimeRun(1,500,NULL); TimeRun(2,1000,Test123); TestKillTimer(1); //TestKillTimer(2);
关于微秒级延时函数详细介绍参考:http://blog.csdn.net/a29562268/article/details/68955533!
相关文章推荐
- Windows下的高精度定时器实现及精确时刻获取
- Windows下的高精度定时器实现及精确时刻获取
- 定时器:为 Windows 实现一个连续更新,高精度的时间供应器
- Windows下的高精度定时器实现及精确时刻获取
- Windows下的高精度定时器实现及精确时刻获取
- 定时器:为 Windows 实现一个连续更新,高精度的时间供应器
- Windows下的高精度定时器实现及精确时刻获取
- Windows下的高精度定时器实现及精确时刻获取
- Visual C++实现微秒级精度定时器
- VC++实现微秒级的精确定时器
- Visual C++实现微秒级精度定时器
- Linux时间子系统之六:高精度定时器(HRTIMER)的原理和实现
- QueryPerformanceCounter实现Windows微秒级延时
- windows下实现微秒级的延时
- Visual C++实现微秒级精度定时器
- 高精度定时器(Windows)
- windows下实现微秒级延时
- windows下实现微秒级的延时
- C#实现高精度定时器
- Linux时间子系统之六:高精度定时器(HRTIMER)的原理和实现