阅读了《Unix/Linux系统编程》中关于定时器及时钟服务的部分,结合网上资料进行了整理

1. 相关概念

基于X86架构的个人计算机有数个定时器,包括实时时钟RTC、可编程间隔定时器PIT、多核CPU中的本地定时器、高分辨率定时器。

实时时钟RTCRTC由一个小型备用电池供电,即使计算机关机时,它也能够连续运行。RTC用于实时提供时间和日期信息。由于RTC在电脑关机时继续运行,因此可以解释为什么开机后系统显示的时间与现实中保持一致。时间变量是一个长整数,即从1970年1月1日起经过的秒数

2. 时钟相关系统调用与库函数

2.1 gettimeofday系统调用

返回当前时间即当前秒数和微秒数。其中秒数是相对于1970年1月1日0点所经过的秒数。

int gettimeofday(struct timeval * tv, struct timezone * tz)
  • 参数tv指向一个timeval结构体变量,该变量保存返回的时间结果。

    timeval结构体定义如下:tv_sec成员保存秒数,tv_usec成员保存微秒数

    struct timeval{__time_t tv_sec;        /* Seconds.  */__suseconds_t tv_usec;   /* Microseconds.  */};
    
  • 第二个参数类型timezone已过期,使用NULL即可。

2.2 settimeofday系统调用

设置系统时间

int settimeofday(const struct timeval *tv, const struct timezone *tz)
  • 第一个参数tv即为要设置的系统时间
  • 第二个参数类型timezone已过期,使用NULL即可

2.3 ctime库函数

以日历形式显示当前日期和时间。

char * ctime(const time_t * timer)
  • 参数是指向 time_t 变量的指针,该变量即为从1970年开始的秒数。
  • 返回值是一个C字符串,该字符串以日历形式表示当前日期和时间。

示例:获取当前时间并以日历形式显示

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
int main(){struct timeval t;gettimeofday(&t,NULL);//获取当前系统时间printf("cur time is : %s",ctime(&t.tv_sec));//以日历形式打印当前时间
}

运行结果

xtark@xtark-vmpc:~/桌面/linux_study/section5$ gcc test.c
xtark@xtark-vmpc:~/桌面/linux_study/section5$ ./a.out
cur time is : Sat Jun 19 10:38:22 2021

2.4 time系统调用

以秒为单位返回当前时间(从1970年到现在的秒数)。该系统调用缺点是时间精度是秒而不是微秒

time_t time(time_t * timer)
  • 参数timer:如果该参数不是NULL,除了返回当前时间外,还将当前时间存储在timer中
  • 返回值:当前时间

2.5 clock函数

返回程序执行起(一般为程序的开头)到调用该函数时,占用CPU的时间(时钟计时单元)

clock_t clock(void)
  • 返回值是自程序启动起,处理器时钟所使用的时间。如果失败,则返回 -1 值。

在time.h文件中,还定义了一个常量CLOCKS_PER_SEC,用来表示一秒钟会有多少个时钟计时单元

#define CLOCKS_PER_SEC  ((clock_t) 1000000)

在Linux系统中,CLOCKS_PER_SEC表示的值可能不同。这里该宏定义表示1000000,因此每个时钟计时单元表示一微秒,即程序执行一微妙,clock函数的返回值就+1。

因此,为了获取 CPU 所使用的秒数,需要除以 CLOCKS_PER_SEC。

clock_t c = clock();//获取该程序从开始到现在占用CPU的时间(时钟计时单元)
printf("%f\n",(double)c/CLOCKS_PER_SEC);//打印出占用CPU的秒数

需要注意,clock返回的是占用CPU的时间,因此如果进程不是处于运行态(即不占用CPU时),那么该时间不算在clock返回值内

示例:进程sleep 5秒,然后打印占用CPU时间

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>
int main(){sleep(5);clock_t c = clock();printf("%f\n",(double)c/CLOCKS_PER_SEC);
}

运行结果:可以看出该进程占用CPU时间仅有0.000618秒,即sleep的时间并不算在clock函数返回值内,因为进程sleep时不占用CPU。

xtark@xtark-vmpc:~/桌面/linux_study/section5$ gcc test.c
xtark@xtark-vmpc:~/桌面/linux_study/section5$ ./a.out
0.000618

2.6 times系统调用

参考资料

用于获取进程的具体执行时间,将结果保存在tms类型变量中

clock_t times(struct tms * buffer)
  • 参数buffer:保存进程具体执行时间,tms结构体类型:

    struct tms{clock_t tms_utime;  /* User CPU time.  进程在用户模式下花费 CPU 时间*/clock_t tms_stime;  /* System CPU time. 进程在系统模式(内核)下花费 CPU 时间 */clock_t tms_cutime; /* User CPU time of dead children. 已死掉子进程在用户模式下花费 CPU 时间*/clock_t tms_cstime; /* System CPU time of dead children.  已死掉子进程在系统(内核)模式下花费 CPU 时间*/
    };
    
  • 返回值:返回自过去某个任意时间点以来所经过的时钟刻度的数量。 返回值可能溢出clock_t类型的时钟数。 出错时,返回-1,并适当设置 errno。

2.7 间隔定时器

参考资料

Linux为每个进程提供了三种不同类型的间隔计时器,可用作进程计时。

通过setitimer系统调用创建间隔定时器

2.7.1 setitimer系统调用

创建间隔定时器。通过which参数指定不同种类的定时器,当间隔定时器到期时,会向进程发送一个信号(即为发送给进程进行处理的一个数字1-31),并将定时器重置为指定的间隔值

int setitimer(int which, const struct itimerval * new_value, struct itimerval * old_value)
  • 参数which:间隔定时器类型。总共有三种定时器类型

    • ITIMER_REAL实时定时器,以系统真实的时间来计算,到期时它发出SIGALRM(14)信号。

    • ITIMER_VIRTUAL以该进程在用户态下花费的CPU时间来计算,它发出SIGVTALRM(26)信号。

    • ITIMER_PROF以该进程在用户态下和内核态下所费的CPU时间来计算。它发出SIGPROF(27)信号。

  • 参数new_value:指向itimerval结构体变量,用来对计时器进行设置。

    struct itimerval{/* 定时器过期时放入'it_value'的值(定时器过期时重置的下一次间隔时长)。  */struct timeval it_interval;/* 当前时刻距离定时器下一次到期的时长(初始定时时间)。  */struct timeval it_value;};
    

    其中timeval结构体:

    struct timeval{__time_t tv_sec;        /* 秒  */__suseconds_t tv_usec;  /* 微秒  */};
    

    setitimer工作机制是,先对it_value倒计时,当it_value为零时触发信号。然后重置为it_interval。继续对it_value倒计时。一直这样循环下去。

    如果 new_value.it_value 中的任一字段不为零,则定时器在指定时间初始到期。 如果 new_value.it_value 中的两个字段都为零,则定时器被解除。因此使用setitimer系统调用创建定时器时new_value.it_value中的两个字段不能都是0,不然就解除定时器了。

    如果只指定it_value,即it_interval为零it_value大于0,仅仅会延时而不会定时(也就是说仅仅会触发一次信号)。

  • 参数old_value:指向itimerval结构体变量。通常使用不上,即设置为NULL。用来存储上一次setitimer调用时设置的new_value值。

2.7.2 getitimer系统调用

函数getitimer()将由which指定的定时器的当前值放入cur_value指向的变量。

int getitimer(int __which, struct itimerval *cur_value)

cur_value.it_value是距离下一次到期还有多少时间。 这个值随着定时器的倒计时而变化,并在定时器到期时被重置为 it_interval。 如果it_value的两个字段都是零,那么这个定时器目前是被解除的(不活动)。

cur_value.it_interval为定时器的间隔值。如果it_interval的两个字段都是0,那么这是一个单次定时器(也就是说,它只延时一次,而不会定时间隔)。

2.7.3 间隔定时器示例

创建实时定时器

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
//信号处理函数
void func(int sig)
{printf("signal : %d\n",sig);
}
int main()
{signal(SIGALRM, func);//注册信号处理函数struct itimerval new_value;new_value.it_value.tv_sec = 1;//初始延时1秒new_value.it_value.tv_usec = 0;new_value.it_interval.tv_sec = 2;//定时器间隔2秒new_value.it_interval.tv_usec = 0;setitimer(ITIMER_REAL, &new_value, NULL);//创建定时器while(1);
}

需要注意ITIMER_REAL定时器无论进程是否正在执行都进行定时。而另外两种定时器ITIMER_VIRTUAL和ITIMER_PROF仅在占用CPU时才进行定时(即进程处于运行态时才计时)。如下面的例子:

创建ITIMER_PROF定时器,并将进程sleep 5秒后进入while(1)死循环

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
void func(int sig)
{printf("signal : %d\n",sig);
}
int main(int argc, char *argv[])
{signal(SIGPROF, func);struct itimerval new_value;new_value.it_value.tv_sec = 0;new_value.it_value.tv_usec = 1;//初始延时1微秒new_value.it_interval.tv_sec = 0;new_value.it_interval.tv_usec = 500000;//定时器间隔0.5sprintf("begin timer\n");setitimer(ITIMER_PROF, &new_value, NULL);sleep(5);//sleep 5秒printf("5 seconds left \n");while(1);
}

运行结果:可见进程在sleep时由于不占用CPU所以不会使得ITIMER_PROF计时

xtark@xtark-vmpc:~/桌面/linux_study/section5$ gcc test.c
xtark@xtark-vmpc:~/桌面/linux_study/section5$ ./a.out
begin timer
5 seconds left
signal : 27
signal : 27
signal : 27
signal : 27
signal : 27

Linux 定时器 setitimer相关推荐

  1. linux上的定时器上的jiffies,linux定时器和Jiffies汇.doc

    linux定时器和Jiffies汇 1.linux HZ Linux核心几个重要跟时间有关的名词或变数,将介绍HZ.tick与jiffies. HZ Linux核心每隔固定周期会发出timer int ...

  2. 二十二、linux定时器

    一.Linux 定时器介绍 在 Linux 内核中, 定时器叫做内核定时器, 内核定时器用于控制某个函数, 也就是定时器将要处理的函数在未来的某个特定的时间内执行. 内核定时器注册的处理函数只执行一次 ...

  3. Linux定时器接口

    Linux定时器接口主要分为三类: 一. sleep(), unsleep, alarm(),引用了SIGALARM信号,在多线程中使用信号又是相当麻烦的. 二. nanosleep(), clock ...

  4. Linux定时器:无节拍机制tickless(CONFIG_NO_HZ)

    Linux定时器:无节拍机制tickless(CONFIG_NO_HZ) BAT-Battle 2013-09-01 Tickless 机制是Linux 内核中引入的新定时机制 以前,Linux内核会 ...

  5. Linux定时器执行

    Linux定时器执行 Linux系统的定时器执行命令:crontab 1.参数选项: -e:编辑定时执行内容 -l:显示当前定时执行内容 -r:删除当前定时执行内容 -i:在删除用户的crontab之 ...

  6. Linux定时器函数setitimer

    1.介绍 在linux下如果定时如果要求不太精确的话,使用alarm()和signal()就行了(精确到秒),但是如果想要实现精度较高的定时功能的话,就要使用setitimer函数. setitime ...

  7. linux定时器错误使用,linux下定时器的使用

    Linux下定时器的使用主要用到两个函数:setitimer()和getitimer(); 注意:setitimer()一个进程中只能有一个,下一个会覆盖前一个的定时. Linux系统给每个进程提供了 ...

  8. Linux·定时器原理与使用

    目录 定时器的实现原理 内核启动注册时钟中断 内核时钟中断处理流程 内核定时器时间轮算法 定时器的使用方法 一个基于时间轮的定时器简单实现 定时器的实现原理 定时器的实现依赖的是CPU时钟中断,时钟中 ...

  9. 学习笔记3 Linux定时器和sg90舵机的综合应用

    今天学习了Linux的定时器功能,并复刻了学习51单片机时玩的智能感应垃圾桶项目.总体感觉难度不大. 先捏软柿子,sg90舵机,应该是市面上能能买到的最便宜的舵机了吧(我瞎说的,如果不是可以发链接给我 ...

  10. linux定时器(crontab)实例

    linux实验示例----实现每2分钟将"/etc"下面的文件打包存储到"/usr/lobal"目录下 ·Step1:编辑当前用户的crontab并保存 终端输 ...

最新文章

  1. Spring AOP 面向切面编程相关注解
  2. 软件设计原则——接口隔离原则
  3. 麒麟操作系统配置网络_讲解银河麒麟桌面操作系统
  4. guibuilder 皮肤_和平精英返场皮肤投票排名介绍-返场皮肤哪个好
  5. ANN:神经网络堆叠/进化故事( 从感知机到DRBN )
  6. Test of etco
  7. datasnap ajax jsonp,有没有办法在Delphi DataSnap REST服务器上使用JSONP?
  8. FileInputStream 把文件作为字节流进行读操作
  9. idea 编译 maven 项目
  10. android单选按钮空值,Android的 - 空指针异常的对话与单选按钮
  11. IT职场人生系列之四:怎样写简历
  12. 原子变量, 无锁定且无等待算法
  13. 这个低代码报表开发平台,操作类似Excel,用好了不需要加班
  14. python中的pickle解析
  15. tomcat内存溢出全记录
  16. LeetCode——Maxium Depth of Binary Tree
  17. Android自定义SwitchButton左右滑动开关按钮控件
  18. minigui3.2 安装教程
  19. 使用Nordic芯片的手环OTA(android)
  20. crontab命令不执行

热门文章

  1. 一个简单的订单生成器 ---- 20160920
  2. 不止跑路,拯救误操作rm -rf /*的小伙儿
  3. Idea的全局搜索快捷键
  4. 计算机工程信息学院严翔,《频频相见》严翔、严晓频、胡凌虹,交通社出品,有容书邦发行著【摘要 书评 在线阅读】-苏宁易购图书...
  5. 一次性计时器和间隔性计时器的实现
  6. 录音文件的比特率的计算方法
  7. 常见的笔记本电池使用技巧
  8. 测试第一步,雀氏纸尿裤
  9. 炼数成金(dataguru)IT技能修炼
  10. react 实现图片的滚动缩放和按住鼠标左键移动图片效果