文章目录

  • alarm
  • setitimer
  • timer_create
  • timer_delete
  • timer_settime
  • timer_gettime
  • timer_getoverrun



定时器(timer)相当于系统每隔一段时间给进程发一个定时信号,需要定义一个信号处理函数。

alarm

unsigned int alarm(unsigned int seconds)

设置一个定时器,在接下来的某个时刻该定时器会超时,发生超时后,产生SIGALRM信号。
产生信号后,忽略或者不捕获此信号终止调用该alarm函数的进程;捕获此信号,根据信号处理程序采取动作。

setitimer

int setitimer(int which, 
              const struct itimerval *value, 
              struct itimerval *ovalue);
struct itimerval {
	struct timeval it_interval;
	struct timeval it_value;
};
struct timeval {
	long tv_sec;
	long tv_usec;
};

which为定时器类型
ITIMER_REAL:以系统真实的时间来计算,它送出SIGALRM信号。
it_interval:指定间隔时间,it_value指定初始定时时间。如果只指定it_value就是实现一次定时;如果同时指定 it_interval,则超时后,系统会重新初始化it_value为it_interval,实现重复定时;两者都清零,则会清除定时器。

timer_create

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
}

功能:进程创建的定时器,定时器是每个进程自己的,不是在fork时继承的。
参数:
clock_id:说明定时器是基于哪个时钟,取值如下:
CLOCK_REALTIME / CLOCK_MONOTONIC / CLOCK_PROCESS_CPUTIME_ID
CLOCK_THREAD_CPUTIME_ID/ CLOCK_REALTIME_HR/ CLOCK_MONOTONIC_HR
timerid:保存被创建的定时器ID
evp:指定了定时器到期要产生的异步通知
如果evp为NULL,那么定时器到期会产生默认的信号,对CLOCK_REALTIMER来说,默认信号就是SIGALRM。对那些定时器到期时要产生除默认信号之外的其它信号的定时器来说,必须将sigev_signo设置为期望的信号码。
sigev_notify说明了定时器到期时应该采取的行动。通常这个成员的值为SIGEV_SIGNAL说明在定时器到期时,会产生一个信号。可以将sigev_notify设为SIGEV_NONE来防止定时器到期时产生信号。

如果几个定时器产生了同一个信号,处理程序可以用sigev_value来区分是哪个定时器产生了信号。要实现这种功能必须在为信号安装处理程序时,使用struct sigaction的成员sa_flags中的标志符SA_SIGINFO

通过将sigev_notify设定为如下值来定制定时器超时后的行为:
SIGEV_SIGNAL:发送由evp->sigev_sino指定的信号到调用进程,evp->sigev_value的值将被作为siginfo_t结构体中si_value的值。
SIGEV_NONE:什么都不做,只提供通过timer_gettime和timer_getoverrun查询超时信息。
SIGEV_THREAD:sigev_notification_attributes为线程属性创建一个线程,在新建的线程内部以sigev_value为参数调用sigev_notification_function。

timer_delete

int timer_delete(timer_t timerid);

删除ID为timerid的POSIX:TMR定时器

timer_settime

int timer_settime(timer_t timerid, int flags, 
                  const struct itimerspec *value, 
                  struct itimerspec *ovalue)
struct itimerspec{
    struct timespec it_interval;  //定时器周期值
    struct timespec it_value;  //定时器到期值
};

timer_settime负责启动或停止timer_create创建的定时器
参数
flag:说明定时器使用的是相对时间还是绝对时间
vaule:指向的值来设置timerid指定的定时器
ovalue:不为NULL,timer_settime就将定时器以前的值放在ovalue指定的位置上
如果定时器正在运行,那么*ovalue的成员it_value非零,并包含了定时器到期之前剩余的时间
TIMER_ABSTIME表示绝对时间;
如果flag没有设定为TIMER_ABSTIME,则定时器从调用开始在it_value内超时;
如果设定为TIMER_ABSTIME,该函数表现为时间直到下一次超时被设定为it_value指定的绝对时间和与timerid相联的时钟值的差值。
定时器的再装由value的it_interval成员值来设定。

timer_gettime

int timer_gettime(timer_t timerid,struct itimerspec *value);

获得一个活动定时器的剩余时间。

timer_getoverrun

int timer_getoverrun(timer_t timerid);

有可能一个定时器到期了,而同一定时器上一次到期时产生的信号还处于挂起状态。在这种情况下,其中的一个信号可能会丢失。这就是定时器超限。通过调用timer_getoverrun来确定一个特定的定时器出现这种超限的次数。定时器超限只能发生在同一个定时器产生的信号上。由多个定时器,甚至是那些使用相同的时钟和信号的定时器,所产生的信号都会排队而不会丢失。

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

static int count = 0;
static struct itimerval oldtv;
void set_timer(){
    struct itimerval itv;
    itv.it_interval.tv_sec = 1;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 1;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &itv, &oldtv);
}
void signal_handler(int m){
    count++;
    printf("%d\n", count);
}  
int main(){
    signal(SIGALRM, signal_handler);
    set_timer();
    while(count < 10000);
    exit(0);
    return 1;
}
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <time.h>
void my_handler(int signo, siginfo_t *info, void *context){
    char *p;    
    p = (char *)info->si_value.sival_ptr;
    printf("%s", p);
}
int main(void){
    struct sigaction act;
    timer_t timer_id;
    struct sigevent evp;
    char buf[1024];
    struct itimerspec it = {{1,0}, {1,0}};

    memset(&act, 0, sizeof(act));
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = my_handler;
    sigaction(SIGALRM, &act, NULL);

    evp.sigev_notify = SIGEV_SIGNAL;
    evp.sigev_signo = SIGALRM;
    evp.sigev_value.sival_ptr = (void *)buf;

    timer_create(CLOCK_REALTIME, &evp, &timer_id);
    timer_settime(timer_id, 0, &it, NULL);

    while(1);
    return 0;
}