LINUX RTC机制实现计时器类

来源:互联网 发布:视频画面定格软件 编辑:程序博客网 时间:2024/05/16 09:25

在LINUX中经常要使用计时器,而在LINUX环境下使用计时器不像WINDOWS环境下那样一个SETTIMER()方便,主要有三种方式:使用SLEEP/USLEEP+单独线程;SETITMER加处理信号SIGALRM,或者是RTC机制。这里我讲到的是使用RTC机制实现计时器类。这种方法最为优越,它与传统意义上的SLEEP和SIGALRM信号是分离的,它的运行不受SLEEP的影响,而像SETITMER等都会受到SLEEP的影响,因为它们使用的是同一时钟。
    以前用select实现的计时器类(http://hi.baidu.com/susdisk/blog/item/03f70d35e8e2e182a61e1288.html)其实并不是真正的计时器,它是一个循环,只是在处理完一次ONTIMER()事件后停下了一秒,然后再接着一次ONTIMER(),这其实并不是真正的计时器。真正的计时器应该是不管是否在处理ONTIMER()事件,它都会触发。
    RTC(real-time clock)。现在可以使用LINUX下的RTC机制来编写计时器类,这个类是完全意义上的计时器,经过测试,也基本不占用cpu时间,因为它采用的是底层的硬件时钟,rtc的文档中说的很明白,它与系统时钟最大的区别在于即使它在机器耗能非常低的情况下,也会触发此时钟信号。它也与SLEEP、SETITIMER等函数是完全独立的,就是说,使用这个计时器类,你依然可以使用各种SLEEP函数等,互不影响,这一点我觉得是最重要的。
    实现如下:

[cpp] view plaincopy
  1. CTimer.h:  
  2. /* 
  3. * CTimer.h 
  4. * 
  5. * Created on: 2009-7-13 
  6. *      Author: DEAN 
  7. */  
  8. //////////////////////////////////////////////////////////////  
  9. // This class provide a timer to finish some works.  
  10. // Call StartTimer() to enable it and call StopTimer() to stop  
  11. // it. The work you want to do should be written on OnTimer()  
  12. // function. Call SetInterval(x) to set every x second to call  
  13. // OnTimer() once.  
  14. //////////////////////////////////////////////////////////////  
  15. #ifndef CTIMER_H_  
  16. #define CTIMER_H_  
  17. #include <sys/time.h>  
  18. #include <linux/rtc.h>  
  19. #include <sys/ioctl.h>  
  20. #include <pthread.h>  
  21. class CTimer  
  22. {  
  23. private:  
  24.     static CTimer *g_singleinstance;  
  25.     long m_second, m_counter;  
  26.     unsigned long m_data;  
  27.     int m_rtcfd;  
  28.     pthread_t thread_timer;  
  29.     static void *thread_stub(void *p)  
  30.     {  
  31.         (static_cast<CTimer*>(p))->thread_proc();  
  32.     }  
  33.     void *thread_proc();  
  34.     void OnTimer();  
  35. protected:  
  36.     CTimer();  
  37. public:  
  38.     virtual ~CTimer();  
  39.     static CTimer *Instance();  
  40.     void SetInterval(long second);  
  41.     void StartTimer();  
  42.     void StopTimer();  
  43. };  
  44. #endif /* CTIMER_H_ */  
  45. CTimer.cpp:  
  46. /* 
  47. * CTimer.cpp 
  48. * 
  49. * Created on: 2009-7-13 
  50. *      Author: dean 
  51. */  
  52. #include "Timer.h"  
  53. #include <iostream>  
  54. #include <sys/time.h>  
  55. #include <linux/rtc.h>  
  56. #include <sys/ioctl.h>  
  57. #include <sys/types.h>  
  58. #include <sys/stat.h>  
  59. #include <fcntl.h>  
  60. #include <pthread.h>  
  61. using namespace std;  
  62. CTimer *CTimer::g_singleinstance = 0;  
  63. CTimer::CTimer():  
  64.     m_second(2), m_counter(0)  
  65. {  
  66.     //Init the rtc  
  67.     m_rtcfd = open("/dev/rtc", O_RDONLY);  
  68.     if(m_rtcfd < 0)  
  69.     {  
  70.         cout<<"TimerWarning: open /dev/rtc error..."<<endl;  
  71.         return;  
  72.     }  
  73.     if(ioctl(m_rtcfd, RTC_IRQP_SET, 2) < 0)  
  74.     {  
  75.         cout<<"TimerWarning: Set rtc request failed..."<<endl;  
  76.         close(m_rtcfd);  
  77.         return;  
  78.     }  
  79.     pthread_create(&thread_timer, NULL, thread_stub, this);  
  80. }  
  81. //////////////////////////private methods//////////////////////////  
  82. void *CTimer::thread_proc()  
  83. {  
  84.     int nfds;  
  85.     while(true)  
  86.     {  
  87.         read(m_rtcfd,&m_data,sizeof(unsigned long));  
  88.         ++m_counter;  
  89.         if (m_counter >= m_second)  
  90.         {  
  91.             OnTimer();  
  92.             m_counter = 0;  
  93.         }  
  94.         pthread_testcancel();  
  95.     }  
  96. }  
  97. void CTimer::OnTimer()  
  98. {  
  99.     cout<<"Timer...."<<endl;  
  100. }  
  101. //////////////////////////public methods//////////////////////////  
  102. CTimer::~CTimer()  
  103. {  
  104.     pthread_cancel(thread_timer);  
  105.     pthread_join(thread_timer, NULL);  
  106.     close(m_rtcfd);  
  107. }  
  108. CTimer *CTimer::Instance()  
  109. {  
  110.     if (g_singleinstance == 0)  
  111.         g_singleinstance = new CTimer;  
  112.     return g_singleinstance;  
  113. }  
  114. void CTimer::SetInterval(long second)  
  115. {  
  116.     m_second = second * 2;  
  117. }  
  118. void CTimer::StartTimer()  
  119. {  
  120.     if (!(m_rtcfd > 0))  
  121.     {  
  122.         cout<<"TimerWarning: rtcfd < 0...Start failed..."<<endl;  
  123.         return;  
  124.     }  
  125.     if(ioctl(m_rtcfd, RTC_PIE_ON, 0) < 0)  
  126.     {  
  127.         cout<<"TimerWarning: ioctl(RTC_PIE_ON) failed..."<<endl;  
  128.         close(m_rtcfd);  
  129.         return;  
  130.     }  
  131.     m_counter = 0;  
  132. }  
  133. void CTimer::StopTimer()  
  134. {  
  135.     if (!(m_rtcfd > 0))  
  136.     {  
  137.         cout<<"TimerWarning: rtcfd < 0...Stop failed..."<<endl;  
  138.         return;  
  139.     }  
  140.     if(ioctl(m_rtcfd, RTC_PIE_OFF, 0) < 0)  
  141.     {  
  142.         cout<<"TimerWarning: ioctl(RTC_PIE_ON) failed..."<<endl;  
  143.         close(m_rtcfd);  
  144.         return;  
  145.     }  
  146. }  
 

 


[cpp] view plaincopy
  1. linux 下 timer机制 标准实现,一般是用 sigalarm + setitimer() 来实现的,但这样就与 select/epoll 等逻辑有所冲突,我希望所有 event 的通知逻辑都从 select/epoll 中触发。(FreeBSD 中 kqueue 默认就有 FILTER_TIMER,多好)  
  2.   
  3. ps. /dev/rtc 只能被 open() 一次,因此上面希望与 epoll 合并的想法基本不可能了~  
  4.   
  5. 下面是通过 /dev/rtc (real-time clock) 硬件时钟实现的 timer机制。:-)  
  6. 其中 ioctl(fd, RTC_IRQP_SET, 4) 的第三个参数只能是 2, 4, 8, 16, 32 之一,表示 xx Hz。  
  7.   
  8. -------------------------------------------------  
  9. #include <linux/rtc.h>  
  10. #include <sys/ioctl.h>  
  11. #include <sys/time.h>  
  12. #include <sys/types.h>  
  13. #include <fcntl.h>  
  14. #include <stdio.h>  
  15. #include <unistd.h>  
  16. #include <errno.h>  
  17. #include <time.h>  
  18. #include <err.h>  
  19.   
  20. int main(void)  
  21. {  
  22.         unsigned long i = 0;  
  23.         unsigned long data = 0;  
  24.         int fd = open("/dev/rtc", O_RDONLY);  
  25.   
  26.         if ( fd < 0 )  
  27.                 errx(1, "open() fail");  
  28.   
  29.         /* set the freq as 4Hz */  
  30.         if ( ioctl(fd, RTC_IRQP_SET, 4) < 0 )  
  31.                 errx(1, "ioctl(RTC_IRQP_SET) fail");  
  32.   
  33.         /* enable periodic interrupts */  
  34.         if ( ioctl(fd, RTC_PIE_ON, 0) < 0 )  
  35.                 errx(1, "ioctl(RTC_PIE_ON)");  
  36.   
  37.         for ( i = 0; i < 100; i++ )  
  38.         {  
  39.                 if ( read(fd, &data, sizeof(data)) < 0 )  
  40.                         errx(1, "read() error");  
  41.   
  42.                 printf("timer %d/n", time(NULL));  
  43.         }  
  44.   
  45.         /* enable periodic interrupts */  
  46.         if ( ioctl(fd, RTC_PIE_OFF, 0) < 0 )  
  47.                 errx(1, "ioctl(RTC_PIE_OFF)");  
  48.   
  49.   
  50.         close(fd);  
  51.         return 0;  
  52. }  

0 0
原创粉丝点击