定时器

1、Linux定时器的使用(信号)

1.1 Alarm

alarm用在不需要经确定时的时候,返回之前剩余的秒数

它可以在进程中设置一个定时器,当定时器指定的时间到时,它向进程发送SIGALRM信号。如果忽略或者不捕获此信号,则其默认动作是终止调用该alarm函数的进程。

要注意的是,一个进程只能有一个闹钟时间,如果在调用alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。需要注意的是,经过指定的秒数后,信号由内核产生,由于进程调度的延迟,所以进程得到控制从而能够处理该信号还需要一些时间

如果有以前为进程登记的尚未超时的闹钟时钟,而且本次调用的seconds值是0,则取消以前的闹钟时钟,其余留值仍作为alarm函数的返回值。

#include<unistd.h>

成功:如果调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。

出错:-1

Ep1:

#include <stdio.h>

#include <unistd.h>

#include <sys/time.h>

#include <signal.h>

void func(int n)

{

         printf("2 s reached.\n");

}

 

int main()

{

         signal(SIGALRM, func); //不捕获该信号时进程终止

         //当定时器指定的时间到时,它向进程发送SIGALRM信号。

         //如果忽略或者不捕获此信号,则其默认动作是终止调用该alarm函数的进程

         alarm(2);

         while (1);

         return 0;

}

 

Ep2:

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

int main(void)

{

         int ret = alarm(5);

         printf("%d\n", ret);//则返回上一个闹钟时间的剩余时间

         sleep(3);

         ret = alarm(10);//以前的闹钟时间2都被新值10所代替

         printf("%d\n", ret);//则返回上一个闹钟时间的剩余时间

 

         //(10后受到闹钟发出的SIGALRM),程序结束

         pause();//令目前的程序暂停(进入休眠状态,直到被信号(signal)所中断

         return 0;

}

 

1.2 linux内置定时器- setitimer

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

which为定时器类型,setitimer支持3种类型的定时器:

ITIMER_REAL: 以系统真实的时间来计算(不管进程在何种模式下运行(甚至在进程被挂起时),它总在计数),它送出SIGALRM信号。

ITIMER_VIRTUAL: -以该进程在用户态即程序执行时)下花费的时间来计算(计算进程执行的时间),它送出SIGVTALRM信号。

ITIMER_PROF: 以该进程在用户态下(即程序执行时)和内核态下(即进程调度用时)所费的时间来计算,它送出SIGPROF信号, ITIMER_PROF记录的时间比ITIMER_VIRTUAL多了进程调度所花的时间。

setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。

setitimer()调用成功返回0,否则返回-1

参数介绍

/* Type of the second argument to `getitimer' and

   the second and third arguments `setitimer'.  */

struct itimerval

  {

    /* Value to put into `it_value' when the timer expires.  */

    struct timeval it_interval; //则超时后,系统会重新初始化it_valueit_interval,实现重复定时

    /* Time to the next timer expiration.  */

    struct timeval it_value;//指定初始定时时间

  };

 

it_interval指定间隔时间,it_value指定初始定时时间。如果只指定it_value,就是实现一次定时;如果同时指定 it_interval,则超时后,系统会重新初始化it_value为it_interval,实现重复定时;两者都清零,则会清除定时器。

/* A time value that is accurate to the nearest

   microsecond but also has a range of years.  */

struct timeval

  {

    __time_t tv_sec;            /* Seconds.  */

    __suseconds_t tv_usec;   /* Microseconds.  */

  };

tv_sec提供秒级精度,tv_usec提供微秒级精度,以值大的为先,注意1s = 1000 000us

ovalue用来保存先前的值,常设为NULL

实例

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include <time.h>

#include <sys/time.h>

 

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;

         }

         fflush(stdout);

         return;

}

 

//在该例子中,每隔一秒发出一个SIGALRM,每隔0.5秒发出一个SIGVTALRM信号

int main()

{

         struct itimerval value, ovalue, value2; //(1)

         printf("process id is %d\n", getpid());

         signal(SIGALRM, sigroutine);

         signal(SIGVTALRM, sigroutine);

         //setting it_value is one seconds

         value.it_value.tv_sec = 1;

         value.it_value.tv_usec = 0;

    //setting it_interval value is one seconds

         value.it_interval.tv_sec = 1;

         value.it_interval.tv_usec = 0;

         //每隔一秒发送一次送出SIGALRM信号(以系统真实的时间来计算)

         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;

         //每隔0.5秒发出一个SIGVTALRM信号

         setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

         while(true);

}

1.3 sleep,usleep实现定时器

#include <signal.h>

#include <unistd.h>

#include <string.h>

#include <stdio.h>

static char msg[] = "I received a msg.\n";

int len;

void show_msg(int signo)

{

         write(STDERR_FILENO, msg, len);

}

 

int main()

{

         struct sigaction act;

         union sigval tsval;

         act.sa_handler = show_msg;//代表新的信号处理函数

         act.sa_flags = 0;

         sigemptyset(&act.sa_mask);//清空此信号集

         //参数signum = 50 可以指定SIGKILLSIGSTOP以外的所有信号

         sigaction(50, &act, NULL);

         len = strlen(msg);

         while (1)

         {

                   sleep(2); /*睡眠2*/

                   /*向主进程发送信号,实际上是自己给自己发信号*/

                   sigqueue(getpid(), 50, tsval);//sigqueue()发送信号

         }

         return 0;

}

1.4 时间差

#include <signal.h>

#include <unistd.h>

#include <string.h>

#include <stdio.h>

#include <time.h>

static char msg[] = "I received a msg.\n";

int len;

static time_t lasttime;

void show_msg(int signo)

{

         write(STDERR_FILENO, msg, len);

}

int main()

{

         struct sigaction act;

         union sigval tsval;

         act.sa_handler = show_msg;//代表新的信号处理函数

         act.sa_flags = 0;

         sigemptyset(&act.sa_mask);//清空此信号集

         //参数signum = 50 可以指定SIGKILLSIGSTOP以外的所有信号

         sigaction(50, &act, NULL);

         len = strlen(msg);

         time(&lasttime);

         while (1)

         {

                   time_t nowtime;

                   /*获取当前时间*/

                   time(&nowtime);

                   /*和上一次的时间做比较,如果大于等于2秒,则立刻发送信号*/

                   if (nowtime - lasttime >= 2)

                   {

                            /*向主进程发送信号,实际上是自己给自己发信号*/

                            sigqueue(getpid(), 50, tsval);//sigqueue()发送信号

                            lasttime = nowtime;

                   }

         }

         return 0;

}

注:使用CPU时间替换系统时间计算时间差更精确

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值