linux 下 alarm(), setitimer 定时器与 POSIX 定时器 timer_settime()对比总结 (上)

1.  alarm() 函数 

适用于精度要求不高的场景,比如几秒。

函数原型:

unsigned int alarm(unsigned int seconds);

函数说明:

该种定时器方法是通过alarm()函数和signal()函数配合完成,alarm函数用来定时,当到达定时的时间后,内核会发送SIGALARM信号给进程,默认会结束进程。也可以通过signal函数为信号SIGALRM设置处理函数,若参数seconds 为0,则之前设置的闹钟会被取消,并将剩下的时间返回;

函数返回值:如果进程设置了闹钟时间,在调用alarm()之后,则返回上一个闹钟时间,否则返回0,出错返回-1。

alarm()执行后,进程将继续执行,在后期(alarm以后)的执行过程中将会在seconds秒后收到信号SIGALRM并执行其处理函数。

示例1:

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> //alarm的库
int count;
void sigalrm_func(int sig){
    count++;
    printf("alarm![%d]\n",count);
    alarm(1);
    printf("over\n");
    return; 
}

int main(int argc,char *argv[])
{
    signal(SIGALRM, sigalrm_func);
    alarm(2);
    printf("see\n");
    while(1)
    {
        if(count == 3)
        break;
    }

 }

程序先是等待定时2秒然后发送信号触发调用函数,然后在调用函数每一秒再设置一次alarm触发调用函数,结果如下:

示例2:

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

 int main(int argc, char *argv[])
 {
    sigset_t block;

    sigemptyset(&block);
    sigaddset(&block, SIGALRM);
    sigprocmask(SIG_BLOCK, &block, NULL);

    while (1) {
        printf("%ld\n", time(NULL));
        alarm(3);
        printf("see\n");
        sigwaitinfo(&block, NULL);
    }
     return 0;
 }

输出结果:

其中几个函数解释:

sigwaitinfo()函数:

#include <signal.h>
int sigwaitinfo(sigset_t *set, siginfo_t *info)

阻塞一个进程直到特定信号发生,但信号到来时不执行信号处理函数,而是返回信号值。 调用该函数的典型代码为:

sigwaitinfo();
sigset_t newmask;
int rcvd_sig;
siginfo_t info;
sigemptyset(&newmask);
sigaddset(&newmask, SIGRTMIN);
sigprocmask(SIG_BLOCK, &newmask, NULL);
rcvd_sig = sigwaitinfo(&newmask, &info);
if(rcvd_sig == -1)
{
    //…...
}

其中:

1. siget_t 信号集定义为一种数据类型,用来描述信号的集合:

    typedef struct{
    unsigned long sig[_NSIG_WORDS];
     }sigset_t

2.int sigemptyset(sigset_t* set)

函数说明:用来将参数set信号集初始化并清空。

返回值:成功返回0,错误返回-1。

3.int sigaddset(sigset_t* set, int signum)

函数说明:用来将signum代表的信号加入至参数set信号集里。

返回值:成功返回0,错误返回-1。

4.int sigpromask(int how, const sigset_t* set, sigset_t* oldset)

函数说明:用来改变目前的信号遮罩,其操作依参数how来决定。

返回值:成功返回0,错误返回-1。

5.void (signal(int signum, void( handler)(int)))(int);

函数说明: signal()会依据参数signum指定的信号编号来设置该信号的处理函数,当指定的信号到达时就会跳转参数handler指定的函数执行。

返回值:返回先前的信号处理函数指针,如果有错误返回SIG_ERR(-1)

示例3:

不同情况的alarm的返回值

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
unsigned a;
void fun(int sig)
{
       if(sig== SIGALRM)
       printf("gettimer alarm!\n");
       else
       printf("gettimer failed!\n");
}
int main(int argc,char *argv[])
{
       unsigned int a,b;
       alarm(6);
       sleep(2);
       a = alarm(3);
       printf("The rest time of the first alarm is %u s\n",a);
       b = alarm(2);
       signal(SIGALRM,fun);
       int i = 0;
       for(i=0;i<3;i++)
       {
              printf("%d\n",i);
              sleep(1);
       }
       printf("The return valuable of the last alarm is %u s\nend\n",b);
       return 0;
}

输出结果:

2.  setitimer()

setitimer()为Linux的API,不同于C语言的StandardLibrary。setitimer()有两个功能,

一是指定一段时间后,才执行某个function,类似alarm,但是精度更高;

二是每间隔一段时间就调用某个函数;

函数原型:

int setitimer(int which, const struct itimerval *new_value,
            struct itimerval *old_value);

需要包含头文件 #include <sys/time.h>

其中:

which: 指定定时器类型 ,setitimer 支持三种类型定时器:

ITIMER_REAL: 以系统真实的时间来计算,发送SIGALRM信号。

ITIMER_VIRTUAL: -以该进程在用户态下花费的时间来计算,发送SIGVTALRM信号。

ITIMER_PROF: 以该进程在用户态下和内核态下所费的时间来计算,发送SIGPROF信号。

new_value, old_value 皆为itimerval  结构的实例:

struct itimerval 
{  
     struct timerval it_interval;  //指定间隔时间
     struct timerval it_value;  //指定初始定时时间
}

 
struct timeval {
    time_t      tv_sec;         // 秒
    suseconds_t tv_usec;        // 微妙 
};

itimeval由两个timeval结构体组成,timeval包含tv_sec和tv_usec两部分,其中tv_sec为秒,tv_usec为微秒(即1/1000000秒)
其中的new_value参数用来对计时器进行设置,it_interval为计时间隔,it_value为延时时长,下面例子中表示的是在setitimer方法调用成功后,延时1微秒便触发一次SIGALRM信号,以后每隔200毫秒触发一次SIGALRM信号。

settimer工作机制是,先对it_value倒计时,当it_value为零时触发信号,然后重置为it_interval,继续对it_value倒计时,一直这样循环下去。

基于此机制,setitimer既可以用来延时执行,也可定时执行。

假如it_value为0是不会触发信号的,所以要能触发信号,it_value得大于0;如果it_interval为零,只会延时,不会定时(也就是说只会触发一次信号)。

old_value参数,通常用不上,设置为NULL,它是用来存储上一次setitimer调用时设置的new_value值。

示例1 :

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

int count = 0;
void set_timer()
{
    struct itimerval itv;
    memset(&itv,0,sizeof(itv));
    itv.it_interval.tv_sec = 1;//每隔1秒
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 3;//第一次3秒
    itv.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &itv, NULL);
    if(ret)
    {
        printf("setitimer failed!/n");
    }
}
void sigalrm_handler(int sig)
{
    if(sig == SIGALRM)
    {
        count++;
        printf("caught signal.. %d\n", count);
    }
    else
    {
        printf("caught signal failed!\n");	
    }	
}
int main()
{
    signal(SIGALRM, sigalrm_handler);
    set_timer();
    while (count < 5)
    {}
    exit(0);
}

输出结果:

示例2: 阻塞的例子

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
int main(int argc, char *argv[])
{
    sigset_t block;
    struct itimerval itv;

    sigemptyset(&block);
    sigaddset(&block, SIGALRM);
    sigprocmask(SIG_BLOCK, &block, NULL);

    itv.it_interval.tv_sec = 2;
    itv.it_interval.tv_usec = 0;
    itv.it_value = itv.it_interval;
    setitimer(ITIMER_REAL, &itv, NULL);

    while (1) 
    {
        printf("%ld\n", time(NULL));
        printf("see\n");
        sigwaitinfo(&block, NULL);
    }
    return 0;
}

输出结果:

关于POSIX 定时器 详细总结请看下一篇

linux 下 alarm(), setitimer 定时器与 POSIX 定时器 timer_settime()对比总结 (下)

参考链接:

定时器函数SetTime与setitimer

linux c stitimer 用法说明

Linux下的定时器以及POSIX定时器:timer_settime()

 

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ppipp1109

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值