LINUX RTC机制实现计时器类

 

在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函数等,互不影响,这一点我觉得是最重要的。
    实现如下:

CTimer.h: /* * CTimer.h * * Created on: 2009-7-13 * Author: DEAN */ ////////////////////////////////////////////////////////////// // This class provide a timer to finish some works. // Call StartTimer() to enable it and call StopTimer() to stop // it. The work you want to do should be written on OnTimer() // function. Call SetInterval(x) to set every x second to call // OnTimer() once. ////////////////////////////////////////////////////////////// #ifndef CTIMER_H_ #define CTIMER_H_ #include <sys/time.h> #include <linux/rtc.h> #include <sys/ioctl.h> #include <pthread.h> class CTimer { private: static CTimer *g_singleinstance; long m_second, m_counter; unsigned long m_data; int m_rtcfd; pthread_t thread_timer; static void *thread_stub(void *p) { (static_cast<CTimer*>(p))->thread_proc(); } void *thread_proc(); void OnTimer(); protected: CTimer(); public: virtual ~CTimer(); static CTimer *Instance(); void SetInterval(long second); void StartTimer(); void StopTimer(); }; #endif /* CTIMER_H_ */ CTimer.cpp: /* * CTimer.cpp * * Created on: 2009-7-13 * Author: dean */ #include "Timer.h" #include <iostream> #include <sys/time.h> #include <linux/rtc.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> using namespace std; CTimer *CTimer::g_singleinstance = 0; CTimer::CTimer(): m_second(2), m_counter(0) { //Init the rtc m_rtcfd = open("/dev/rtc", O_RDONLY); if(m_rtcfd < 0) { cout<<"TimerWarning: open /dev/rtc error..."<<endl; return; } if(ioctl(m_rtcfd, RTC_IRQP_SET, 2) < 0) { cout<<"TimerWarning: Set rtc request failed..."<<endl; close(m_rtcfd); return; } pthread_create(&thread_timer, NULL, thread_stub, this); } //////////////////////////private methods////////////////////////// void *CTimer::thread_proc() { int nfds; while(true) { read(m_rtcfd,&m_data,sizeof(unsigned long)); ++m_counter; if (m_counter >= m_second) { OnTimer(); m_counter = 0; } pthread_testcancel(); } } void CTimer::OnTimer() { cout<<"Timer...."<<endl; } //////////////////////////public methods////////////////////////// CTimer::~CTimer() { pthread_cancel(thread_timer); pthread_join(thread_timer, NULL); close(m_rtcfd); } CTimer *CTimer::Instance() { if (g_singleinstance == 0) g_singleinstance = new CTimer; return g_singleinstance; } void CTimer::SetInterval(long second) { m_second = second * 2; } void CTimer::StartTimer() { if (!(m_rtcfd > 0)) { cout<<"TimerWarning: rtcfd < 0...Start failed..."<<endl; return; } if(ioctl(m_rtcfd, RTC_PIE_ON, 0) < 0) { cout<<"TimerWarning: ioctl(RTC_PIE_ON) failed..."<<endl; close(m_rtcfd); return; } m_counter = 0; } void CTimer::StopTimer() { if (!(m_rtcfd > 0)) { cout<<"TimerWarning: rtcfd < 0...Stop failed..."<<endl; return; } if(ioctl(m_rtcfd, RTC_PIE_OFF, 0) < 0) { cout<<"TimerWarning: ioctl(RTC_PIE_ON) failed..."<<endl; close(m_rtcfd); return; } } 

 

linux 下 timer机制 标准实现,一般是用 sigalarm + setitimer() 来实现的,但这样就与 select/epoll 等逻辑有所冲突,我希望所有 event 的通知逻辑都从 select/epoll 中触发。(FreeBSD 中 kqueue 默认就有 FILTER_TIMER,多好) ps. /dev/rtc 只能被 open() 一次,因此上面希望与 epoll 合并的想法基本不可能了~ 下面是通过 /dev/rtc (real-time clock) 硬件时钟实现的 timer机制。:-) 其中 ioctl(fd, RTC_IRQP_SET, 4) 的第三个参数只能是 2, 4, 8, 16, 32 之一,表示 xx Hz。 ------------------------------------------------- #include <linux/rtc.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <time.h> #include <err.h> int main(void) { unsigned long i = 0; unsigned long data = 0; int fd = open("/dev/rtc", O_RDONLY); if ( fd < 0 ) errx(1, "open() fail"); /* set the freq as 4Hz */ if ( ioctl(fd, RTC_IRQP_SET, 4) < 0 ) errx(1, "ioctl(RTC_IRQP_SET) fail"); /* enable periodic interrupts */ if ( ioctl(fd, RTC_PIE_ON, 0) < 0 ) errx(1, "ioctl(RTC_PIE_ON)"); for ( i = 0; i < 100; i++ ) { if ( read(fd, &data, sizeof(data)) < 0 ) errx(1, "read() error"); printf("timer %d/n", time(NULL)); } /* enable periodic interrupts */ if ( ioctl(fd, RTC_PIE_OFF, 0) < 0 ) errx(1, "ioctl(RTC_PIE_OFF)"); close(fd); return 0; }

你可能感兴趣的:(thread,linux,timer,filter,null,FreeBSD)