Linux下定时的实现

30 篇文章 0 订阅
5 篇文章 0 订阅

转载自:http://www.cnblogs.com/feisky/archive/2010/03/20/1690561.html

使用定时器的目的无非是为了周期性的执行某一任务,或者是到了一个指定时间去执行某一个任务。要达到这一目的,一般有两个常见的比较有效的方法。

一个是用linux内部的三个定时器:ITIME_REAL,ITIMER_VIRTUAL,ITIME_PROF;

另一个是用sleep, usleep函数让进程睡眠一段时间;

其实,还有一个方法,那就是用gettimeofday(), difftime()等自己来计算时间间隔,然后时间到了就执行某一任务,但是这种方法效率低,所以不常用

1. 系统提供的定时器

linux操作系统为每一个进程提供的3个内部计时器:

ITIMER_REAL: 给一个指定的时间间隔,按照实际的时间来减少这个计数,当时间间隔为0的时候发出SIGALRM信号

ITIMER_VIRTUAL: 给定一个时间间隔,当进程执行的时候才减少计数,时间间隔为0的时候发出SIGVTALRM信号

ITIMER_PROF: 给定一个时间间隔,当进程执行或者是系统为进程调度的时候,减少计数,时间到了,发出SIGPROF信号,这个和ITIMER_VIRTUAL联合,常用来计算系统内核时间和用户时间。

用到的函数有:

#include < sys/time.h >
 
int
getitimer (int which ,struct itimerval * value ) ;
int
setitimer (int which ,struct itimerval * newvalue ,struct itimerval * oldvalue ) ;

用到的数据结构有:
strcut
timeval
{
    long
tv_sec ; /*秒*/
    long
tv_usec ; /*微秒*/
} ;
 
struct
itimerval
{
    struct
timeval it_interval ;/*时间间隔*/
    struct
timeval it_value ;   /*当前时间计数*/
} ;
it_interval用来指定每隔多长时间执行任务, it_value用来保存当前时间离执行任务还有多长时间。
比如说, 你指定it_interval为2秒(微秒为0),开始的时候我们把it_value的时间也设定为2秒(微秒为0),当过了一秒, it_value就减少一个为1, 再过1秒,则it_value又减少1,变为0,这个时候发出信号(告诉用户时间到了,可以执行任务了),并且系统自动把it_value的时间重置为it_interval的值,即2秒,再重新计数

struct sigaction
{

    void     (*sa_handler)(int);

    void     (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t   sa_mask;
    int        sa_flags;
    void     (*sa_restorer)(void);
};

其中,sa_handler是一个指针,指向信号处理函数;

与后面两种实现方式的主要区别:
由于 定时器时系统自身提供的,所以时间到了之后,消息也是由 系统自动传给消息队列的;
而后两种由于是用户自己实现,所以必须将进程ID和信号ID传送到消息队列(通过sigqueue()函数来实现)。

使用步骤:

1. 初始化定时器的类型和时间间隔;

2. 初始化信号的类型和回调函数;

3. 设定时间到了后,回调函数执行;

示例:

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

//信号回调函数
void sign_proc(int signo)
{
    printf("time is running out\n");
}

//建立信号处理机制
void init_sigaction()
{
    struct sigaction signact;
    //指定有信号之后的回调函数
    signact.sa_handler=sign_proc;
    signact.sa_flags=0;
    //初始化信号集
    sigemptyset(&signact.sa_mask);
    //指定信号类型,注意与定时器类型保持一致
    sigaction(SIGALRM, &signact, NULL);
}

//设置定时器
void init_time()
{
    struct itimerval interval;
    //初始值
    interval.it_value.tv_sec=5;
    interval.it_value.tv_usec=0;
    //间隔时间
    interval.it_interval=interval.it_value;
    //设置定时器类型为:ITIMER_REAL
    setitimer(ITIMER_REAL, &interval, NULL);
}

int main()
{
    init_time();
    init_sigaction();
    while(1);
    return 0;
}
说明:程序设定定时器类型为实时定时器:ITMER_REAL,每隔5秒钟都会发送一个SIGALRM信号,当主函数接收到了这个信号之后,调用信号处理函数sign_proc处理。

对于ITIMER_VIRTUAL和ITIMER_PROF的使用方法类似,当你在setitimer里面设置的定时器为ITIMER_VIRTUAL的时候,你把sigaction里面的SIGALRM改为SIGVTALARM, 同理,ITIMER_PROF对应SIGPROF。

2. 通过sleep以及usleep实现定时

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

void show_msg(int signo)
{
    printf("time is using up\n");
}

int main()
{
    struct sigaction signact;
    union sigval tsval;

    //设定信号的回调函数
    signact.sa_handler=show_msg;
    signact.sa_flags=0;
    //初始化信号集
    sigemptyset(&signact.sa_mask);

    sigaction(50, &signact, NULL);

    while(1)
    {
        sleep(2);
        sigqueue(getpid(), 50, tsval);
    }

    return 0;
}

看到了吧,这个要比上面的简单多了,而且你用秒表测一下,时间很准,指定2秒到了就给你输出一个字符串。所以,如果你只做一般的定时,到了时间去执行一个任务,这种方法是最简单的。

3. 通过自己计算时间差的方法来定时

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

void sign_proc(int signo)
{
    printf("time is running out\n");
}

int main()
{
    struct sigaction signact;
    union sigval tsval;
    
    //设置信号变量
    signact.sa_handler=sign_proc;
    signact.sa_flags=0;

    sigemptyset(&signact.sa_mask);
    sigaction(50, &signact, NULL);

    time_t oldtime;
    time(&oldtime);
    while(1)
    {
        time_t nowtime;
        time(&nowtime);
        
        if(nowtime-oldtime>=2)
        {
            //将进程ID,信号ID放到消息机制中
            sigqueue(getpid(), 50, tsval);
            oldtime=nowtime;
        }
    }
}

这种做法效率比较低,一般很少使用。

这个和上面不同之处在于,是自己手工计算时间差的,如果你想更精确的计算时间差,你可以把 time 函数换成gettimeofday,这个可以精确到微妙。

上面介绍的几种定时方法各有千秋,在计时效率上、方法上和时间的精确度上也各有不同,采用哪种方法,就看你程序的需要。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值