`
fp_moon
  • 浏览: 970563 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Linux下时间和定时器

 
阅读更多

http://blog.chinaunix.net/u1/35065/showart_1870601.html
重点读了第三种方法。文章写得很好,加了一点点注释

可参考 http://linux.die.net/man/3/timer_settime
              http://linux.die.net/man/2/setitimer 
              http://opengroup.org/onlinepubs/007908799/xsh/timer_settime.html

---毫秒---微秒---纳秒 (数量级:1000

一、问题的提出
我们开发程序时,经常会遇到时间和定时器的问题,为了更好的使用时间和定时器,现在列举一个一些时间结构体、函数和定时器。

二、解决思路
1.
时间类型
1) time_t
是一个长整型,一般用来表示用1970年以来的秒数。

2)struct timeval有两个成员,一个是秒,一个是微妙。

struct timeval
{             
long tv_sec;        /* seconds */        
long tv_usec;   /* microseconds */  
};

3) struct timespec有两个成员,一个是秒,一个是纳秒。

struct timespec
{
   time_t tv_sec;          /* seconds */
   long    tv_nsec;        /* nanoseconds */
};

4) struct tm是直观意义上的时间表示方法

struct tm
{                  
int     tm_sec;         /* seconds */                   
int     tm_min;         /* minutes */                     
int     tm_hour;        /* hours */                  
int     tm_mday;         /* day of the month */                        
int     tm_mon;         /* month */                    
int     tm_year;        /* year */                  
int     tm_wday;         /* day of the week */                        
int     tm_yday;        /* day in the year */                          
int     tm_isdst;        /* daylight saving time */           
};

5)

     struct timeb
     {
        time_t    time;            //
1970来经过的秒数

        unsigned short millitm; //
毫秒
        short     timezone;        //
时区
        short     dstflag;//
为日光节约时间的修正值,如果为非0代表启用日光节约修正
};

   6)

      struct timezone
{
         int tz_minuteswest;//
和格林尼治时间相差多少分

         int tz_dsttime;//
日光节约时间的状态 
};

   日光节约时间:夏时制。

2.时间函数
1) char *asctime(const struct tm *timeptr)

将时间和日期以字符串格式显示。

2clock_t clock(void)

   取得进程占用cpu的大约时间。

3char *ctime(const time_t *timep)

将时间和日期以字符串格式显示。

4) double difftime(time_t time1, time_t time0)

计算时间time1time0间的差距。

5) int ftime(struct timeb *tp)

   取得目前的时间和日期。

6) int gettimeofday(struct timeval *tv, struct timezone *tz)

   取得目前的时间。

7strcut tm *gmtime(const time_t *timep)

   time_t结构时间转tm结构时间,tmUTC时区。

8) struct tm *localtime(const time_t *timep)

   time_t结构时间转tm结构时间,tm是当地时区。

9time_t mktime(struct tm *timeptr)

   tm结构时间转换为time_t

10) int settimeofday(const struct timeval *tv, const struct timezone *tz)

   设置时间为tv,设置时区为tz

11) size_t strftime(char *s, size_t max, const char *format, const struct tm *tm)

   将参数tm的时间结构依照参数format所指定的字符串格式做转换,转换后的字符串将复制到参数s所指的字符串数组中,该字符串的最大长度为参数max所控制。

12) time_t time(time_t *t)

   取得目前的时间,时间按照UTC

13) void tzset(void)

   从环境变量TZ取得目前当地的时间。

3.延迟函数
主要的延迟函数有:sleep(),usleep(),nanosleep(),select(),pselect().

1) unsigned int sleep(unsigned int seconds)

延时seconds秒。

2) void usleep(int micro_seconds)

延时 micro_seconds微妙

3) int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)

延时的时间为rqtp,如果nansleep被信号中断,且rmtp不为NULL,则rmtp指定的位置上包含的就是剩余时间。

4) int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

如果将readfds, writefds, exceptfds置为NULLtimeout为非零,则延时timeout

5) int pselect(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec tsptr, const sigset_t *sigmask)

如果将readfds, writefds, exceptfds置为NULLtsptr为非零,则延时tsptr

3.定时器
1) unsigned int alarm(unsigned int seconds)

设置一个定时器,在seconds秒后超时,当定时器超时时,产生SIGALRM信号。如果不忽略或不捕捉此信号,则其默认动作是终止调用该alarm函数的进程,如果设置了SIGALRM信号处理函数,则会执行该信号处理函数。

每个进程只能有一个闹钟时钟。如果在调用alarm时,以前已为该进程设置过闹钟时钟,而且它还没有超时,则将该闹钟时钟的余留值作为本次alarm函数调用的值返回,以前登记的闹钟时钟则被新值代替。

例子:

void sigalrm_fn(int sig)

{

printf("alarm!\n");

alarm(2);

return;

}

 

int main(void)

{

signal(SIGALRM, sigalrm_fn);

alarm(1);

while(1) pause();

}

 

2) POSIX:XSI间隔定时器

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

struct itimerval

{
    struct timeval it_interval; /*
计时器重启动的间歇值
*/
    struct timeval it_value;    /*
计时器安装后首先启动的初始值
*/
};

 

   getitimer()用计时器的当前值填写value指向的结构体。
setitimer()
value指向的结构体设为计时器的当前值,如果ovalue不是NULL,将返回计时器原有值。

which:间歇计时器类型,有三种选择:

l         ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM

l         ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值(虚拟时间),发送的信号是SIGVTALRM

l         ITIMER_PROF //数值为2,虚拟时间和进程的系统时间递减,发送的信号是SIGPROF

itimerval结构中的it_value是减少的时间,当这个值为0的时候就发出相应的信号了. 然后再将it_value设置为it_interval. 也就是先处理it_value中设置的值,为0后发送信号(根据which来判断发送什么信号),之后都是根据it_interval的值发送信号。若it_valueit_interval都为0,也就没有相应的信号产生了。

alarm()一样,由于信号的限制,POSIX:XSI间隔定时器对于每个进程来说最多只有3个定时器。

例子:

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;

}

return;

}

 

int main()

{

struct itimerval value, ovalue, value2;

sec = 5;

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

signal(SIGALRM, sigroutine);

signal(SIGVTALRM, sigroutine);

value.it_value.tv_sec = 1;

value.it_value.tv_usec = 0;

value.it_interval.tv_sec = 1;

value.it_interval.tv_usec = 0;

setitimer(ITIMER_REAL, &value, &ovalue);

value2.it_value.tv_sec = 0;

value2.it_value.tv_usec = 500000;

value2.it_interval.tv_sec = 0;

value2.it_interval.tv_usec = 500000;

setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

for(;;)

;

}

3)POSIX:TMR间隔定时器

int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)

   进程可以通过调用timer_create()创建特定的定时器,定时器是每个进程自己的,不是在fork时继承的。timer_create的参数clock_id说明定时器是基于哪个时钟的,*timerid装载的是被创建的定时器的IDtimer_create函数创建了定时器,并将他的ID放入timerid指向的位置中。参数evp指定了定时器到期要产生的异步通知。如果evpNULL,那么定时器到期会产生默认的信号,对CLOCK_REALTIMER来说,默认信号就是SIGALRM。对那些定时器到期时要产生除默认信号之外的其它信号的定时器来说,程序必须将evp->sigev_signo设置为期望的信号码。struct sigevent 结构中的成员evp->sigev_notify说明了定时器到期时应该采取的行动。通常,这个成员的值为SIGEV_SIGNAL,这个值说明在定时器到期时,会产生一个信号。程序可以将成员evp->sigev_notify设为SIGEV_NONE来防止定时器到期时产生信号。

 

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

clock_id的取值为以下:

CLOCK_REALTIME :Systemwide realtime clock.

CLOCK_MONOTONIC:Represents monotonic time. Cannot be set.

CLOCK_PROCESS_CPUTIME_ID :High resolution per-process timer.

CLOCK_THREAD_CPUTIME_ID :Thread-specific timer.

CLOCK_REALTIME_HR :High resolution version of CLOCK_REALTIME.

CLOCK_MONOTONIC_HR :High resolution version of CLOCK_MONOTONIC.

 

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

}

通过将evp->sigev_notify设定为如下值来定制定时器到期后的行为:

l         SIGEV_SIGNAL: 发送由evp->sigev_sino指定的信号到调用进程,evp->sigev_value的值将被作为siginfo_t结构体中si_value的值。

l         SIGEV_NONE:什么都不做,只提供通过timer_gettimetimer_getoverrun查询超时信息。

l         SIGEV_THREAD: evp->sigev_notification_attributes为线程属性创建一个线程,在新建的线程内部以evp->sigev_value为参数调用evp->sigev_notification_function

 

int timer_delete(timer_t timerid);

删除IDtimeridPOSIX:TMR定时器。

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说明定时器使用的是相对时间还是绝对时间。相对时间与POSIX:XSI定时器使用的策略类似,而绝对时间的精确度更高。参数vaule指向的值来设置timerid指定的定时器。如果ovalue不为NULLtimer_settime就将定时器以前的值放在ovalue指定的位置上。如果定时器正在运行,那么*ovalue的成员it_value非零,并包含了定时器到期之前剩余的时间。

TIMER_ABSTIME表示绝对时间;
如果flag没有设定为TIMER_ABSTIME,则定时器从调用开始在it_value内超时;value->it_value代表计时器第一次超时的时间。
如果设定为TIMER_ABSTIME,该函数表现为时间直到下一次超时被设定为it_value指定的绝对时间和与timerid相联的时钟值的差值。如果已经到了it_value指定的值,那么超时后的处理就会立即执行。

定时器的再装由valueit_interval成员值来设定。



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

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

int timer_getoverrun(timer_t timerid);

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

例子:

编译方法:

     gcc -o example example.c   -lrt   -lpthread   

那个rt库就是POSIX   realtime   extension的库。

 

#include   <stdio.h>  

#include   <time.h>  

#include   <signal.h>  

#include   <string.h>//不然会出现对memset函数的警告

void  

handle   (union sigval   v)  

{  

      time_t   t;  

      char   p[32];  

 

      time   (&t);  

      strftimep,   sizeof   (p),   "%T",   localtime   (&t));  

      printf("%s   thread   %lu,   val   =   %d,   signal   captured.\n",   p,   pthread_self(), v.sival_int);  

      return;  

}  

   

int create   (int   seconds,   int   id)  

{  

      timer_t   tid;  

      struct   sigevent   se;  

      struct   itimerspec   ts,   ots;  

      memset   (&se,   0,   sizeof   (se));  

      se.sigev_notify   =   SIGEV_THREAD;  

      se.sigev_notify_function   =   handle;  

      se.sigev_value.sival_int   =   id;   //作为handle()的参数

      if   (timer_create   (CLOCK_REALTIME,   &se,   &tid)   <   0)  

          {  

              perror   ("timer_creat");  

              return   -1;  

          }  

      puts   ("timer_create   successfully.");  

      ts.it_value.tv_sec   =   3;  

      ts.it_value.tv_nsec   =   0;  

      ts.it_interval.tv_sec   =   seconds;  

      ts.it_interval.tv_nsec   =   0;  

      if   (timer_settime (tid,   TIMER_ABSTIME,   &ts,   &ots)   <   0)  

          {  

              perror   ("timer_settime");  

              return   -1;  

          }  

      return   0;  

}  

   

int   main   (void)  

{  

      create   (3,   1);  

      create   (5,   2);  

      for   (;;)  

          {  

              sleep   (10);  

          }  

}

三、总结
Linux
下定时器主要使用上面介绍的三种定时器。

 

分享到:
评论

相关推荐

    linux下多定时器+线程池的实现(经典)

    //linux只允许单进程拥有一个定时器,因此在linux下的单进程中要使用多个定时器,则需要自己维护管理 // //这个实现允许用户使用多个自定义的定时器,每个自定义的定时器将周期地被触发直到其被删除。实现的主要思路...

    Linux下一种高性能定时器池的实现

    本文提出一种linux用户空间下的一种高性能定时器池的实现方法,实现主要基于时间轮和红黑树,以及linux内核提供了一种利于管理的定时器句柄timerfd。结合红黑树、位图、时间轮等技术,设计一种高性能级定时器池,池...

    linux下的C语言开发(定时器)

    linux下的C语言开发(定时器) 定时器是我们需要经常处理的一种资源。那linux下面的定时器又是怎么一回事呢?其实,在linux里面有一种进程中信息传递的方法,那就是信号。这里的定时器就相当于系统每隔一段时间给...

    Linux时间子系统之六:高精度定时器(HRTIMER)的原理和实现 - DroidPhone的专栏 - 博客频道 - CSDN

    摘要视图订阅登录 | 注册Linux时间管系统(7)01.struct hrtimer {1251838次第1606名51篇0篇4篇555条定时器的到期时间用k

    实用的Linux c 定时器代码

    linux c 开发的定时器,封装为CTimer类,编译运行已通过,包含头文件就可以用,可以节省编码与调试时间,很实用的代码,可以用于项目中的基础库。Timer.h Timer.cpp

    Linux的动态定时器-时间轮

    动态定时器不断地创建和销毁,而且它的运行次数也不受限制。  定时器在内核代码中属于一个基础组件。要想完全弄清楚linux2.6中内核定时器的实现,得先从初始化开始。  在start_kernel(void)–&gt;init_timers(void)...

    【Linux】C-C++ 一种简单易用的高效定时器实现.rar

     该机制主要可以应用在一些要求可以随时取消和修改计时时间的场景,例如收到某条启动指令之后需要启动设备,当超过多长时间没有收到指令时就需要停止设备。优点吧,实现简单,精度较高,好用,不消耗 CPU 资源,...

    基于Linux定时器管理器

    定时器管理器,添加定时器定时处理函数,删除定时器。

    Linux定时器代码

    linux下的与时间相关的开发,定时器方面。

    linux下定时器实现

    以最小堆、红黑树、时间轮三种方式实现定时器,时间轮效率最高,非常具有参考价值!

    Zynq-Linux-Timer中断源码加参考文档

    Zynq-Linux中timer中断的设计源码加axi-timer的参考文档

    一种Linux应用层的定时器实现方法

    Linux应用层的定时器的实现起来很简单,这里介绍一种基于链表的定时器实现方法,在一个循环里面可以实现多个定时器。该方法无需依赖其他的库,你只需设置一个超时时间和相应的执行函数,系统就会在超时的时候执行一...

    Linux系统编程第08期:时间管理和定时器编程

    本期课程是《Linux系统编程》第08期,主要讲解在Linux下时间管理的基本概念、时间的获取和设置、定时器编程,包括简单的闹钟alarm、间隔定时器interval timer、POSIX timer编程。

    linux内核源代码分析-定时器与时间管理.ppt

    linux内核源代码分析-定时器与时间管理.ppt

    linux定时器ppt

    对linux定时器部分知识点进行了很好的梳理和概括

    Linux时间子系统.docx

    这些文件主要讨论了Linux内核中的时间子系统,包括时钟源(clock source)、时间表示、时间维护者(timekeeper)、定时器引擎(clock_event_device)、低分辨率定时器、高精度定时器(HRTIMER)、动态时钟框架...

    hrtimer高精度定时器.odt

    Linux时间子系统:高精度定时器(hrtimer)与普通的定时器相比较,hrtimer具有高精度定时的优势;精度可达纳秒(ns)级别,内核使用红黑树来组织hrtimer。随着系统的运行,hrtimer不停的被创建和销毁。

    实验四Linux中断与异常编程技术

    一个是用linux内部的三个定时器,另一个是用sleep, usleep函数让进程睡眠一段时间,使用alarm定时发出一个信号,还有那就是用gettimeofday, difftime等自己来计算时间间隔,然后时间到了就执行某一任务,但是这种...

Global site tag (gtag.js) - Google Analytics