用法:
#include <sys/time.h>

int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);

 

功能描述:
获取或设定间歇计时器的值。系统为进程提供三种类型的计时器,每一类以不同的时间域递减其值。当计时器超时,信号被发送到进程,之后计时器重启动。

 
参数:
which:间歇计时器类型,有三种选择

ITIMER_REAL //数值为0,以系统真实的时间来计算,发送的信号是SIGALRM。
ITIMER_VIRTUAL //数值为1,以该进程在用户态下花费的时间来计算,发送的信号是SIGVTALRM。
ITIMER_PROF //数值为2, 以该进程在用户态下和内核态下所费的时间来计算,发送的信号是SIGPROF。

 

value,ovalue:时间参数,原型如下

struct itimerval {
    struct timeval it_interval;
    struct timeval it_value;   
};

struct timeval {
    long tv_sec;               
    long tv_usec;              
};

    itimerval结构中的it_value是减少的时间,当这个值为0的时候就发出相应的信号了. 然后再将it_value设置为it_interval值. 也就是先处理it_value中设置的值,为0后发送信号(根据which来判断发送什么信号),之后都是根据it_interval的值发送信号。若 it_value为0,就没有相应的信号产生了。

struct timeval结构体在time.h中的定义为:
struct timeval
{
__time_t tv_sec;            
__suseconds_t tv_usec;     
};
其中,tv_sec为Epoch到创建struct timeval时的秒数,tv_usec为微秒数,即秒后面的零头。比如当前我写博文时的tv_sec为1244770435,tv_usec为442388,即当前时间距Epoch时间1244770435秒,442388微秒。需要注意的是,因为循环过程,新建结构体变量等过程需消耗部分时间,我们作下面的运算时会得到如下结果:
int i;
for (i = 0; i < 4; ++i)
{
gettimeofday(&tv, NULL);
printf("%dt%dn", tv.tv_usec, tv.tv_sec);
sleep(1);
}
442388       1244770435
443119       1244770436
443543       1244770437
444153       1244770438
前面为微秒数,后面为秒数,可以看出,在这个简单运算中,只能精确到小数点后面一到两位,或者可以看出,每进行一次循环,均需花费0.005秒的时间,用这个程序来作计时器显然是不行的,除非精确计算产生的代码消耗时间。

 

getitimer()用计时器的当前值填写value指向的结构体。
setitimer()将 value 指向的结构体设为计时器的当前值,如果ovalue不是NULL,将返回计时器原有值。


返回说明:
成功执行时,返回0。失败返回-1,errno被设为以下的某个值
EFAULT:value 或ovalue是不有效的指针
EINVAL:其值不是ITIMER_REAL,ITIMER_VIRTUAL 或 ITIMER_PROF之一

 

例子:
void sigroutine(int signo)
{
 static int count1=0,count2=0;

 switch (signo)
 {
 case SIGALRM:
  count1++;
  printf("Catch a signal -- SIGALRM n");
  printf("count1 = %dnn", count1);
  signal(SIGALRM, sigroutine);
  break;
 case SIGVTALRM:
  count2++;
  printf("Catch a signal -- SIGVTALRM n");
  printf("count2 = %dnn", count2);
  signal(SIGVTALRM, sigroutine);
  break;
 }
 return;
}

 

int main()
{
 struct itimerval value, ovalue, value2;
 printf("process id is %dn", getpid());

 signal(SIGALRM, sigroutine);
 signal(SIGVTALRM, sigroutine);

 

 value.it_value.tv_sec = 2;
 value.it_value.tv_usec = 0;
 value.it_interval.tv_sec = 3;
 value.it_interval.tv_usec = 0;
 setitimer(ITIMER_REAL, &value, &ovalue);

 

 value2.it_value.tv_sec = 1;
 value2.it_value.tv_usec = 0;
 value2.it_interval.tv_sec = 3;
 value2.it_interval.tv_usec = 0;
 setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

 

 while(1);
}

Linux下的定时器有两种,以下分别介绍:
setitimer()
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
setitimer()比alarm功能强大,支持3种类型的定时器:
ITIMER_REAL : 以系统真实的时间来计算,它送出SIGALRM信号。
ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
ITIMER_PROF : 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。
setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。
setitimer()调用成功返回0,否则返回-1。
下面是关于setitimer调用的一个简单示范,在该例子中,每隔一秒发出一个SIGALRM,每隔0.5秒发出一个SIGVTALRM信号:

#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>

int sec;
void sigroutine(int signo){
    switch (signo){
        case SIGALRM:
            printf("Catch a signal -- SIGALRM \n");
            signal(SIGALRM, sigroutine);
            break;
        case SIGVTALRM:
            printf("Catch a signal -- SIGVTALRM \n");
            signal(SIGVTALRM, sigroutine);
            break;
    }
    return;
}

int main()
{
    struct itimerval value, ovalue, value2; //(1) 
    sec = 5;

    printf("process id is %d\n", getpid());
    signal(SIGALRM, sigroutine);
    signal(SIGVTALRM, sigroutine);

    value.it_value.tv_sec = 10;   //init time value
    value.it_value.tv_usec = 0;
    value.it_interval.tv_sec = 1;  //reinit time value , if the value is zero, stop timer.
    value.it_interval.tv_usec = 0;

    setitimer(ITIMER_REAL, &value, &ovalue); //(2)

    value2.it_value.tv_sec = 0;
    value2.it_value.tv_usec = 500000;
    value2.it_interval.tv_sec = 0;
    value2.it_interval.tv_usec = 500000;

    setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

    for(;;) ;
}

(2) setitimer()
setitimer()为其所在进程设置一个定时器,如果itimerval.it_interval不为0(it_interval的两个域都不为0),则该定时器将持续有效(每隔一段时间就会发送一个信号)

注意:Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于SIGRTMIN(SIGRTMIN=32,SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是:进程每次处理信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调用signal(),重新安装该信号。

 

Logo

更多推荐