Chinaunix首页 | 论坛 | 博客
  • 博客访问: 169005
  • 博文数量: 30
  • 博客积分: 296
  • 博客等级: 二等列兵
  • 技术积分: 407
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-16 21:37
个人简介

a

文章分类

全部博文(30)

文章存档

2016年(1)

2015年(8)

2014年(1)

2013年(11)

2012年(6)

2011年(1)

2010年(2)

分类: C/C++

2015-03-03 16:06:06

关于定时器

近期做了一个项目,需要服务器端按周期向客户端发送信息,需要使用定时器。
windows平台有好多个定时器函数,在这里记录一下我试过的几种。
另外linux下的定时器函数也记录在这儿。

 1. CreateTimerQueueTimer



// 创建并启动定时器
BOOL WINAPI CreateTimerQueueTimer(
 __out         PHANDLE phNewTimer,
 __in          HANDLE TimerQueue,
 __in          WAITORTIMERCALLBACK Callback,
 __in          PVOID Parameter,
 __in          DWORD DueTime,
 __in          DWORD Period,
 __in          ULONG Flags
);
// 删除定时器
BOOL WINAPI DeleteTimerQueueTimer(
 __in          HANDLE TimerQueue,
 __in          HANDLE Timer,
 __in          HANDLE CompletionEvent
);

  • 示例
        

点击(此处)折叠或打开

  1. // 创建定时器
  2. if (!CreateTimerQueueTimer(
  3.                     &timerId, // timer handle
  4. NULL, // the default timer queue
  5.                     (WAITORTIMERCALLBACK)handler, // 回调函数
  6.                     "test", // 传递给回调函数的数据
  7.                     0, // timer启动延迟时间(毫秒)
  8. 1000, // 周期(毫秒)
  9. 0))    // flags
  10.     {
  11.         printf("CreateTimerQueueTimer error.(%d)", GetLastError());
  12.     }

  13. // 回调函数
  14. static void CALLBACK handler(PVOID lpParam, BOOLEAN TimerOrWaitFired)
  15. {
  16. const char* str = (const char*)lpParam;
  17. printf("str=%s\n", str);
  18. }

  19. // 删除定时器
  20. DeleteTimerQueueTimer(
  21. NULL, // NULL, the default timer queue
  22. timerId, // timer handle
  23. INVALID_HANDLE_VALUE);    // 如果此参数设为NULL,有可能导致程序崩溃




2. timeSetEvent


// 创建并启动定时器
MMRESULT timeSetEvent(  
UINT           uDelay,      
UINT           uResolution,   
LPTIMECALLBACK lpTimeProc,  
DWORD_PTR      dwUser,        
UINT           fuEvent);
// 删除定时器
MMRESULT timeKillEvent(UINT uTimerID);

  • 示例

点击(此处)折叠或打开

  1. // 创建定时器
  2. timerId = timeSetEvent(1000, // 周期(毫秒)
  3. 100, // 精度(毫秒)
  4. &handler, // 回调函数
  5. (DWORD_PTR)"test",     // 传递给回调函数的数据
  6. // 定时器种别(一次性或周期性)
  7. TIME_PERIODIC | TIME_KILL_SYNCHRONOUS | TIME_CALLBACK_FUNCTION);
  8.     if (timerId == NULL)
  9.     {
  10.         printf("timeSetEvent error.(%d)", GetLastError());
  11.         return;
  12.     }

  13. // 回调函数
  14. static void CALLBACK handler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
  15. {
  16. const char* str = (const char*)dwUser;
  17. printf("str=%s\n", str);
  18. }

  19. // 删除定时器
  20. timeKillEvent(timerId);

使用此种定时器函数需要依赖库文件Winmm.lib。

3. CreateWaitableTimer


// 创建定时器
HANDLE WINAPI CreateWaitableTimer(
 __in          LPSECURITY_ATTRIBUTES lpTimerAttributes,
 __in          BOOL bManualReset,
 __in          LPCTSTR lpTimerName
);
// 启动定时器
BOOL WINAPI SetWaitableTimer(
 __in          HANDLE hTimer,
 __in          const LARGE_INTEGER* pDueTime,
 __in          LONG lPeriod,
 __in          PTIMERAPCROUTINE pfnCompletionRoutine,
 __in          LPVOID lpArgToCompletionRoutine,
 __in          BOOL fResume
);
// 取消定时器,调用SetWaitableTimer可重新激活定时器
BOOL WINAPI CancelWaitableTimer(
 __in          HANDLE hTimer
);

  • 示例

点击(此处)折叠或打开

  1. // 创建定时器
  2. hTimer = CreateWaitableTimer(
  3.            NULL, // Default security attributes
  4.            FALSE, // Create auto-reset timer
  5.            NULL); // Name of waitable timer
  6. if (hTimer == NULL)
  7. {
  8.         printf("CreateWaitableTimer error.(%d)", GetLastError());
  9.         return;
  10. }
  11.    
  12. liDueTime.LowPart = 0;
  13. liDueTime.HighPart = 0;
  14. // 启动定时器
  15. bSuccess = SetWaitableTimer(
  16.                     hTimer, // Handle to the timer object
  17.                     &liDueTime, // When timer will become signaled
  18.                     1000, // Periodic timer interval
  19.                     handler, // Completion routine
  20.                     "test", // Argument to the completion routine
  21.                     FALSE); // Do not restore a suspended system
  22.     if (!bSuccess)
  23.     {
  24.         printf("SetWaitableTimer error.(%d)", GetLastError());
  25.         return;
  26.     }

  27. // 回调函数
  28. static void CALLBACK handler(
  29.   LPVOID lpArg, // Data value
  30.   DWORD dwTimerLowValue, // Timer low value
  31.   DWORD dwTimerHighValue ) // Timer high value */
  32. {
  33. const char* str = (const char*)lpArg;
  34. printf("str=%s\n", str);
  35. }

  36. // 删除定时器
  37. CancelWaitableTimer(timerId); // 取消激活
  38. CloseHandle(timerId);    // 关闭句柄

在使用此种定时器时,导致阻塞中的函数select返回值不正常,debug版本下返回-1,这个与linux下
中断发生相似,比较好处理,只要重新调用select函数就好了。但是不能理解的是在release版本下,
它返回正常且select的返回值大于1,也就是多个可读写的描述字准备好了,实际并没有,导致
在下面的处理中调用accept函数时出现异常,不知道为什么,只好放弃使用此种定时器。

4. timer_create(linux)


// 创建定时器
int timer_create(clockid_t clockid, struct sigevent *sevp,
timer_t *timerid);
// 启动定时器
int timer_settime(timer_t timerid, int flags,
                         const struct itimerspec *new_value,
                         struct itimerspec *old_value);
// 删除定时器
int timer_delete(timer_t timerid);

  • 示例1(超时启动线程调用回调函数)
        

点击(此处)折叠或打开

  1. // 创建并启动定时器
  2. timer_t timerid;
  3.     struct sigevent sev;
  4.     struct itimerspec its;

  5. /* Create the timer */
  6.     memset(&sev, 0, sizeof(sev));
  7.     sev.sigev_notify = SIGEV_THREAD;
  8.     sev.sigev_notify_function = handler;
  9.     sev.sigev_value.sival_ptr = "test";

  10. if (timer_create(CLOCKID, &sev, &timerid) == -1)
  11.     {
  12.         printf("timer_create error.(%s)", strerror(errno));
  13.         return;
  14.     }

  15. its.it_value.tv_sec = 1;
  16.     its.it_value.tv_nsec = 0;
  17.     its.it_interval.tv_sec = its.it_value.tv_sec;
  18.     its.it_interval.tv_nsec = its.it_value.tv_nsec;


  19.     if (timer_settime(timerid, 0, &its, NULL) == -1)
  20.     {
  21.         printf("timer_settime error.(%s)", strerror(errno));
  22.         return;
  23.     }

  24. // 回调函数(SIGEV_THREAD)
  25. static void handler(union sigval si)
  26. {
  27. const char* str = si.sival_ptr;
  28. printf("str=%s\n", str);
  29. }

  30. // 删除定时器
  31. timer_delete(timerId);

  • 示例2(超时产生信号)
        

点击(此处)折叠或打开

  1. // 创建并启动定时器
  2. #define SIG SIGRTMIN

  3. timer_t timerid;
  4.     struct sigevent sev;
  5.     struct itimerspec its;
  6.     sigset_t mask;
  7.     struct sigaction sa;

  8. /* Establish handler for timer signal */
  9.     sa.sa_flags = SA_SIGINFO;
  10.     sa.sa_sigaction = handler;
  11.     sigemptyset(&sa.sa_mask);
  12.     if (sigaction(SIG, &sa, NULL) == -1)
  13.     {
  14.         printf("sigaction error.(%s)", strerror(errno));
  15.         return;
  16.     }


  17.     /* Block timer signal temporarily */
  18.     sigemptyset(&mask);
  19.     sigaddset(&mask, SIG);
  20.     if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
  21.     {
  22.         printf("sigprocmask error.(%s)", strerror(errno));
  23.         return;
  24.     }


  25.     /* Create the timer */
  26.     memset(&sev, 0, sizeof(sev));
  27.     sev.sigev_notify = SIGEV_SIGNAL;
  28.     sev.sigev_signo = SIG;
  29.     sev.sigev_value.sival_ptr = "test";

  30. if (timer_create(CLOCKID, &sev, &timerid) == -1)
  31.     {
  32.         printf("timer_create error.(%s)", strerror(errno));
  33.         return;
  34.     }


  35.     /* Start the timer */
  36.     its.it_value.tv_sec = 1;
  37.     its.it_value.tv_nsec = 0;
  38.     its.it_interval.tv_sec = its.it_value.tv_sec;
  39.     its.it_interval.tv_nsec = its.it_value.tv_nsec;


  40.     if (timer_settime(timerid, 0, &its, NULL) == -1)
  41.     {
  42.         printf("timer_settime error.(%s)", strerror(errno));
  43.         return;
  44.     }


  45.     if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
  46.     {
  47.         printf("sigprocmask error.(%s)", strerror(errno));
  48.         return;
  49.     }

  50. // 信号处理函数
  51. static void handler(int sig, siginfo_t *si, void *uc)
  52. {
  53. const char* str = si->si_value.sival_ptr;
  54. printf("str=%s\n", str);
  55. }

※ 在solaris系统里好像不支持超时启动线程的方式启动timer, 如果下面这样设置调用timer_create函数,
  此函数会返回错误-1.
  sev.sigev_notify = SIGEV_THREAD


阅读(2367) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~