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)

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

2)clock_t clock(void)

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

3)char *ctime(const time_t *timep)

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

4) double difftime(time_t time1, time_t time0)

计算时间time1和time0间的差距。

5) int ftime(struct timeb *tp)

取得目前的时间和日期。

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

取得目前的时间。

7)strcut tm *gmtime(const time_t *timep)

time_t结构时间转tm结构时间,tm为UTC时区。

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

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

9)time_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置为NULL,timeout为非零,则延时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置为NULL,tsptr为非零,则延时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_value和it_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装载的是被创建的定时器的ID。timer_create函数创建了定时器,并将他的ID放入timerid指向的位置中。参数evp指定了定时器到期要产生的异步通知。如果evp为NULL,那么定时器到期会产生默认的信号,对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_gettime和timer_getoverrun查询超时信息。

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

int timer_delete(timer_t timerid);

删除ID为timerid的POSIX: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不为NULL,timer_settime就将定时器以前的值放在ovalue指定的位置上。如果定时器正在运行,那么*ovalue的成员it_value非零,并包含了定时器到期之前剩余的时间。

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

#include

#include   #include   //不然会出现对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)

{

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)

{

perror   ("timer_settime");

return   -1;

}

return   0;

}

int   main   (void)

{

create   (3,   1);

create   (5,   2);

for   (;;)

{

sleep   (10);

}

}

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

linux上点时间延时,Linux上时间和定时器相关推荐

  1. linux编译c如何延时,linux和windows下,C/C++开发的延时函数,sleep函数

    简介: 函数名: sleep 功 能: 执行挂起一段时间 用 法: unsigned sleep(unsigned seconds); 在VC中使用带上头文件 #include 在gcc编译器中,使用 ...

  2. linux C非阻塞延时,linux 非阻塞式socket编程求助。。

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 一下客户端: #include #include #include #include #include #include #include #includ ...

  3. linux开发板设置时间,开发板上修改时间方法

    之前使用开发板时发现每次开机后,系统的时间都恢复到初始状态1970年. 一. 先说一下时钟的概念,时钟包括硬件时钟和系统时钟,系统时钟就是linux系统显示的时间,用命令date可以显示当前系统时间: ...

  4. 史上最牛的Linux视频教程—兄弟连Linux笔记

    最近在看兄弟连2014年录制的Linux教学视频,沈超和李明这两个活宝讲得确实是精彩,顺着教学视频讲解的逻辑顺序做了一些笔记,教学视频链接https://www.bilibili.com/video/ ...

  5. 提高linux上socket的性能(linux优化),提高 Linux 上 socket 性能

    使用 Sockets API,我们可以开发客户机和服务器应用程序,它们可以在本地网络上进行通信,也可以通过 Internet 在全球范围内进行通信.与其他 API 一样,您可以通过一些方法使用 Soc ...

  6. 史上最牛的Linux教程—兄弟连 --笔记

    技术交流 qq群 922850187 博客网站 www.lczze.cn 第一章 Linux起源 unix,C语言,TCP-IP 可以看作三胞胎,他们结合在一起相互诞生,其他具体自行可以看:计算机组成 ...

  7. linux时间同步windows,win和linux的时间同步方法大全

    1 windows 如何从广域网时间服务器,同步时间? 1)将时间服务器改成,中国科学院国家授时中心 net time /setsntp:210.72.145.44 2)启动时间同步服务 sc sta ...

  8. linux内核和cpu指令集,Linux之父:Intel别浪费时间在AVX512这类指令集、多堆核心才是正道...

    原标题:Linux之父:Intel别浪费时间在AVX512这类指令集.多堆核心才是正道 在最近一次邮件交流中,Linux之父Linus Torvalds对Intel的处理器战略表达意见. 他谈到&qu ...

  9. Linux 中 3 个文件打包上传和下载相关命令详解

    tar 命令 通过 SSH 访问服务器,难免会要用到压缩,解压缩,打包,解包等,这时候tar 命令就是必不可少的一个功能强大的工具.Linux 中最流行的tar是麻雀虽小,五脏俱全,功能强大. 使用t ...

最新文章

  1. python调用百度识别文字接口_python调用百度通用文字识别接口进行验证码识别
  2. C#上位机串口软件开发--第1讲 工程创建
  3. Java:Java的输入类Scanner
  4. Hadoop集群搭建(27)
  5. 如何删除隐藏着的网卡
  6. [java] 找出字符串中出现最多的字符和出现的次数
  7. 【数据库系统】核心知识归纳总结
  8. java怎么将图片文件转流并在jsp前端显示_jsp已经被淘汰了吗?
  9. 关于IE6下用Jquery attr('onclick')问题
  10. Linux汇编调试器EDB
  11. 2022高教社杯全国大学生数学建模竞赛B题解析(更新完结)
  12. 华为 USG6000防火墙管理员密码重置(配置会清空)
  13. 跑马灯实现的三种方式
  14. Parameterize Method (令函数携带参数)
  15. iOS-内购注意 沙盒二次验证
  16. 保研之路——上科大信息学院直硕夏令营
  17. SDNU QLU 2022.10.15 新生赛
  18. 表格怎么拆分成2个的简便操作
  19. OpenCV图片拼接
  20. 从概率上分析“穷不过三代,富不过三代”,且富三代难于穷三代

热门文章

  1. 关于python 和C++使用cv画矩形并填充颜色同时填充文字
  2. IplImage* cvmat* mat 释放
  3. ElasticSearch IK 分词器快速上手
  4. 持续定义Saas模式云数据仓库+BI
  5. “黑天鹅”,正在改变 AI 落地医疗领域的加速度
  6. 学不动?Apache Member 教你评估实用技术的思路
  7. Soloπ:支付宝开源的Android专项测试工具
  8. MySQL 十大常用字符串函数
  9. 报名倒计时 | 「TeaTalk」技术沙龙成都站再来袭!
  10. 阿里云数字政府市场份额第一,同比增速102.57%