linux 下定时器的实现

时间:2022-04-18 02:20:25

最强大的定时器接口来自POSIX时钟系列,其创建、初始化以及删除一个定时器的行动被分为三个不同的函数:timer_create()(创建定时器)、timer_settime()(初始化定时器)以及timer_delete(销毁它)。

创建定时器:

int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)

struct sigevent
{
int sigev_notify; //notification type
int sigev_signo; //signal number
union sigval sigev_value; //signal value
void (*sigev_notify_function)(union sigval);
pthread_attr_t *sigev_notify_attributes;
}
union sigval
{
int sival_int; //integer value
void *sival_ptr; //pointer value
}
启动定时器:

int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspect *ovalue);

struct itimespec{

struct timespec it_interval;

struct timespec it_value;

};
struct timespec{    time_t tv_sec;    long tv_nsec;  };
     如同settimer(),it_value用于指定当前的定时器到期时间。当定时器到期,it_value的值会被更新成it_interval 的值。如果it_interval的值为0,则定时器不是一个时间间隔定时器,一旦it_value到期就会回到未启动状态。timespec的结构提供了纳秒级分辨率
删除定时器:

int timer_delete (timer_t timerid);

    一次成功的timer_delete()调用会销毁关联到timerid的定时器并且返回0。执行失败时,此调用会返回-1并将errno设定会 EINVAL,这个唯一的错误情况代表timerid不是一个有效的定时器

实例:

#include<stdio.h>
#include<iostream>
#include<signal.h>
#include <string.h>
#include<time.h>
#include <stddef.h>
#include <sstream>
#include <iomanip>
using namespace std;

void testfunc(int signo, siginfo_t* info, void* context);
int cnt;

int main(int argc, char *argv[])
{
cnt = 0;
timer_t timeID;
struct sigevent evp;
memset(&evp, 0, sizeof(evp));
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGRTMAX;
evp.sigev_value.sival_ptr = &timeID;

if(timer_create(CLOCK_REALTIME, &evp, &timeID) ==-1 )
{
cout << "err" << endl;
return -1;
}

struct sigaction sigac;
sigemptyset(&sigac.sa_mask);
sigac.sa_flags = SA_SIGINFO;
sigac.sa_sigaction = testfunc;
sigaction(SIGRTMAX, &sigac, NULL);

struct itimerspec it;
it.it_interval.tv_sec = 2;
it.it_interval.tv_nsec = 0;
it.it_value.tv_sec = 2;
it.it_value.tv_nsec = 0;

if(timer_settime(timeID, 0, &it, NULL) == -1)
{
cout << "err" << endl;
timer_delete(timeID);
return -1;
}

while(cnt < 1000);
return 0;
}

void testfunc(int signo, siginfo_t* info, void* context)
{
// cnt++;
// cout << cnt << endl;
struct tm *t;
time_t timer = time(NULL);
t = localtime(&timer);
ostringstream os;
os.fill('0');
os << setw(4) << t->tm_year + 1900 << '-'
<< setw(2) << t->tm_mon + 1 << '-'
<< setw(2) << t->tm_mday << ' '
<< setw(2) << t->tm_hour << ':'
<< setw(2) << t->tm_min << ':'
<< setw(2) << t->tm_sec << ends;
cout << os.str() << endl;
}

//g++ -g -o sigaction sigaction.cpp -lrt


c++形式:

#include<stdio.h>  
#include<iostream>
#include<signal.h>
#include <string.h>
#include<time.h>
#include <stddef.h>
#include <sstream>
#include <iomanip>
using namespace std;



class CTimeTask
{
public:
typedef void(*func)(int signo, siginfo_t* info, void* context);
CTimeTask()
{
memset(&evp, 0, sizeof(evp));
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGRTMAX;
evp.sigev_value.sival_ptr = &timeID;
if(::timer_create(CLOCK_REALTIME, &evp, &timeID) ==-1 )
{
cout << "timer create err" << endl;
return;
}
}
virtual ~CTimeTask()
{}

int excuteTask(int sec, int nsec, func onFunc)
{
struct sigaction sigac;
sigemptyset(&sigac.sa_mask);
sigac.sa_flags = SA_SIGINFO;
sigac.sa_sigaction = onFunc;
sigaction(SIGRTMAX, &sigac, NULL);

struct itimerspec it;
it.it_interval.tv_sec = sec;
it.it_interval.tv_nsec = nsec;
it.it_value.tv_sec = sec;
it.it_value.tv_nsec = nsec;

if(::timer_settime(timeID, 0, &it, NULL) == -1)
{
cout << "set time task err" << endl;
::timer_delete(timeID);
return -1;
}
}
static CTimeTask* getInstance()
{
if(timeTask == NULL)
timeTask = new CTimeTask();
return timeTask;
}
private:
timer_t timeID;
struct sigevent evp;
static CTimeTask *timeTask;
};
CTimeTask* CTimeTask::timeTask = NULL;
#define Task CTimeTask::getInstance()

void testfunc(int signo, siginfo_t* info, void* context)
{
// cnt++;
// cout << cnt << endl;
struct tm *t;
time_t timer = time(NULL);
t = localtime(&timer);
ostringstream os;
os.fill('0');
os << setw(4) << t->tm_year + 1900 << '-'
<< setw(2) << t->tm_mon + 1 << '-'
<< setw(2) << t->tm_mday << ' '
<< setw(2) << t->tm_hour << ':'
<< setw(2) << t->tm_min << ':'
<< setw(2) << t->tm_sec << ends;
cout << os.str() << endl;
}

int main(int argc, char *argv[])
{
//CTimeTask timeTask;
//CTimeTask::getInstance()->excuteTask(2, 0, testfunc);
Task->excuteTask(2, 0, testfunc);
while(1);
return 0;
}



注:

下面所指的signal都是指以前的older signal函数,现在大多系统都用sigaction重新实现了signal函数
1、signal在调用handler之前先把信号的handler指针恢复;sigaction调用之后不会恢复handler指针,直到再次调用sigaction修改handler指针。
:这样,(1)signal就会丢失信号,而且不能处理重复的信号,而sigaction就可以。因为signal在得到信号和调用handler之间有个时间把handler恢复了,这样再次接收到此信号就会执行默认的handler。(虽然有些调用,在handler的以开头再次置handler,这样只能保证丢信号的概率降低,但是不能保证所有的信号都能正确处理)
2、signal在调用过程不支持信号block;sigaction调用后在handler调用之前会把屏蔽信号(屏蔽信号中自动默认包含传送的该信号)加入信号中,handler调用后会自动恢复信号到原先的值。
(2)signal处理过程中就不能提供阻塞某些信号的功能,sigaction就可以阻指定的信号和本身处理的信号,直到handler处理结束。这样就可以阻塞本身处理的信号,到handler结束就可以再次接受重复的信号。
3、sigaction提供了比signal多的多的功能,可以参考man

参考:
http://blog.sina.com.cn/s/blog_71bc0b1901017gxw.html
http://www.ccvita.com/508.html