09 时钟编程——alarm、pause、getitimer、setitimer

1、Alarms

时钟可以用来调度一个将来要做的任务,Unix提供alarm。使用sleep函数添加时延,sleep(n)将当前进程挂起n秒或者在此期间被一个不能忽略的信号到达所唤醒。

sleep()的工作原理:

系统的每个进程都有一个私有的闹钟(alarm clock),这个闹钟很像一个计时器,可以设置一定秒数后闹铃。时间一到,时钟就发送一个信号SIGALRM到进程。除非进程为SIGALRM设置了处理函数,否则信号将杀死这个进程。这就是sleep的原理,sleep函数由3个步骤组成:

  • 为SIGALRM设置一个处理函数
  • 调用alarm(num_seconds);
  • 调用pause挂起进程直到信号到达

alarm和pause系统调用函数:

  • alarm():设置发送信号的计时器,old=alarm(unsigned seconds),等待seconds秒后内核发送SIGALRM信号到这个进程,返回值old为计时器剩余时间。
  • pause():pause挂起调用进程直到一个信号到达。如果调用进程被这个信号终止,pause没有返回。如果调用进程用一个处理函数捕获,在控制从处理函数处返回后pause返回。

2、间隔计时器

新Unix系统使用间隔计时器,有更高的精度,每个进程都有3个独立的计时器,分别是真实时间、用户时间和用户时间+系统时间。

  • ITIMER_REAL:这个计时器计量真实时间=用户代码执行时间+内核代码执行时间+睡眠时间,当这个时间用尽,发送SIGALRM信号。
  • ITIMER_VIRTUAL:只有进程在用户态运行时才计时,当虚拟计时器用尽,发送SIGVTALRM。
  • ITIMER_PROF:这个计时器在进程运行于用户态或该进程调用而陷入内核态时计时。当这个计时器用尽,发送SIGPROF信号。

每个计时器都有两种间隔:初始it_value和重复it_interval,计时器的数据结构类型:it_value和it_interval都是由秒和微秒两部分组成类似一个小数的整数部分和小数部分。

struct itimerval {
               struct timeval it_interval; /* next value */
               struct timeval it_value;    /* current value */
           };

struct timeval {
               time_t      tv_sec;         /* seconds秒 */
               suseconds_t tv_usec;        /* microseconds微秒 */
           };

getitimer和setitimer系统调用:

  • getitimer():result=getitimer(int which,strut itimerval *val),将某个特定的计时器which的当前设置读到val指向的结构中。
  • setitimer():result=setitimer(int which,const strut itimerval *newval,strut itimerval *oldval),将某个特定的计时器which设置为newval指向的结构的值,之前该计时器的设定复制到oldval指向的结构中。which的值为指定的计时器,分别是ITIMER_REAL、ITIMER_VIRTUAL、ITIMER_PROF这三种计时器。

3、总结

计时器用来挂起执行和调度将要采取的动作,一个计时器是内核的一种机制,通过这种机制,内核在一定的时间之后向进程发送SIGALRM信号。alarm系统调用在特定的实际秒数之后发送SIGALRM给进程。setitimer系统调用以更高的精度控制计时器,同时能够以固定的时间间隔发送信号。

4、代码示例

sleep1.c

sleep工作原理展示

#include<stdio.h>
#include<signal.h>
void wakeup()
{
    printf("Alarm received from kernel\n");
}
int main()
{
    printf("about to sleep for 4 seconds\n");
    signal(SIGALRM,wakeup);
    alarm(4);
    pause();
    printf("Morning so soon?\n");
    return 0;
}

ticker_demo.c

演示如何使用一个间隔计时器

#include<stdio.h>
#include<sys/time.h>
#include<signal.h>
void countdown()
{
    static int num=10;
    printf("%d..",num--);
    fflush(stdout);
    if(num<0)
    {
        printf("Done!\n");
        exit(0);
    }
}
int set_ticker(int n_msecs)
{
    struct itimerval new_timeset;
    long n_sec,n_usecs;
    n_sec=n_msecs/1000;
    n_usecs=(n_msecs%1000)*1000L;
    new_timeset.it_interval.tv_sec=n_sec;
    new_timeset.it_interval.tv_usec=n_usecs;
    new_timeset.it_value.tv_sec=n_sec;
    new_timeset.it_value.tv_usec=n_usecs;
    return setitimer(ITIMER_REAL,&new_timeset,NULL);
}
int main()
{
    signal(SIGALRM,countdown);
    if(set_ticker(500)==-1)
        perror("set_ticker");
    else
        while(1)
            pause();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值