UNIX(编程-信号处理):21---getitimer、setitimer函数(struct itimerval、SIGALRM信号、SIGVTALRM信号、SIGPROF信号)

一、定时器种类

  • 系统为每个进程提供三个间隔计时器,每个间隔计时器在不同的时间域中递减。当任何计时器过期时,将向进程发送一个信号,然后计时器(可能)重新启动,计时器的种类如下:
    • ITIMER_REAL(值为0):计时器的值实时递减。计时器超时后,向进程发送SIGALRM信号
    • ITIMER_VIRTUAL(值为1):当进程在执行的过程中计数,仅在进程执行时递减。计时器超时后,发送SIGVTALRM信号
    • ITIMER_PROF(值为2):进程和系统执行时都递减计时器的值。这个计时器通常用于分析应用程序在用户和内核空间中花费的时间。计时器超时后,发送SIGPROF信号

二、struct itimerval结构体

struct itimerval {
    struct timeval it_interval; /* 计时器到期后重新启动的时间间隔 */
    struct timeval it_value;    /* 计时器安装后第一次启动的时间*/
};

struct timeval {
    time_t      tv_sec;  /* seconds,秒 */
    suseconds_t tv_usec; /* microseconds,微秒 */
};
  • struct itimerval结构成员介绍:
    • it_value:是计时器第一次启动到期的时间(到期之后便根据计时器的种类发送对应的信号)
    • it_interval:当计时器第一次启动到期(it_value到期)之后,会将it_value重置为it_interval所指的值,然后每隔it_interval时间执行一次计时器(到期之后便根据计时器的种类发送对应的信号)
  • 计时器停止工作:
    • 如果it_value为0,那么计时器将不生效
    • 如果计时器it_value过期之后,it_interval为0,那么计时器也将停止工作
  • struct timeval结构的tv_sec、tv_usec字段都对计时器的持续时间有重要影响

三、函数介绍

getitimer()函数

#include <sys/time.h>
int getitimer(int which, struct itimerval *curr_value);
  • 功能:计时器的当前值填写在curr_value指向的结构体中
  • 备注:
    • 定时器由ITIMER_REAL、ITIMER_VIRTUAL或ITIMER_PROF之一指定
    • curr_value结构中的it_value字段被设置为计时器上剩余的时间量,如果计时器被禁用,则为零。类似地,it_interval被设置为重置值
  • 参数:
    • which:间歇计时器类型,为上面介绍的3种定时器种类之一
    • curr_value:一个struct itimerval结构体类型,保存当前计时器的值
  • 返回值:成功返回0;出错返回-1,并设置errno值,常见的错误值如下:
    • EFAULT:curr_value无效
    • EINVAL:which参数不是ITIMER_REAL, ITIMER_VIRTUAL,或ITIMER_PROF之一

setitimer()函数

#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value,
              struct itimerval *old_value);
  • 功能:将指定的计时器设置为new_value中的值。如果old_value是非空的,则计时器的旧值存储在那里
  • 参数:
    • which:间歇计时器类型,为上面介绍的3种定时器种类之一
    • new_value:将此参数指向的结构体设为计时器的当前值
    • old_value:如果此参数不为NULL,用来保存计时器原有值
  • 返回值:成功返回0;出错返回-1,并设置errno值
    • EFAULT:new_value或old_value无效
    • EINVAL:which参数不是ITIMER_REAL, ITIMER_VIRTUAL,或ITIMER_PROF之一;或者new_value指向的结构中的tv_usec字段包含0到999999范围之外的值(Linux 2.6.22)

四、定时器注意事项

  • 计时器永远不会在请求的时间之前过期,但是可能会在之后的一些(短)时间过期,这取决于系统计时器的分辨率和系统负载;过期时,将生成一个信号并重置计时器。如果计时器在进程处于活动状态时过期(对于ITIMER_VIRTUAL始终为true),则在生成时将立即发送信号。否则,交付将抵消一个小的时间依赖于系统加载

五、演示案例

  • 下面编程一个程序,定时器种类为ITIMER_REAL,定时器首次在5秒后启动,然后每隔1秒执行一次,发送的信号为SIGALRM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>

void sig_func(int signo);

int main()
{
    //获取当前时间
    time_t current_time;
    (void)time(&current_time);

    //将时间转换为可读的时期和时间格式(struct tm)
    struct tm*tm_ptr;
    tm_ptr=gmtime(&current_time);
    printf("time:%02d:%02d:%2d,main start\n",tm_ptr->tm_hour,tm_ptr->tm_min,tm_ptr->tm_sec);
    

    //为SIGALRM信号绑定处理函数
    signal(SIGALRM,sig_func);
    struct itimerval tick;
    tick.it_value.tv_sec = 5;  //计时器首次在5秒之后启动
    tick.it_value.tv_usec = 0;
	
    tick.it_interval.tv_sec  =1; //定时器第一次到时之后,每隔1秒到期一次
    tick.it_interval.tv_usec = 0;

    //开启一个计时器,种类为ITIMER_REAL,触发的信号为SIGALRM
    int ret = setitimer(ITIMER_REAL, &tick, NULL);

    if ( ret != 0)
    {
        printf("setitimer error:%s \n", strerror(errno) );
        exit(EXIT_FAILURE);
    }

	//pause函数:使进程/线程挂起,在接收到一个信号并从信号处理函数返回之后解除挂起操作
    while(1)
        pause();

    exit(EXIT_SUCCESS);
}

void sig_func(int signo)
{
    time_t current_time;
    (void)time(&current_time);

    struct tm*tm_ptr;
    tm_ptr=gmtime(&current_time);

    //打印时间和信号ID
    printf("time:%02d:%02d:%2d,recv signal %d\n",tm_ptr->tm_hour,tm_ptr->tm_min,tm_ptr->tm_sec,signo);    
}
  • 运行效果如下:

发布了1300 篇原创文章 · 获赞 827 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/103721092