前言
我们日常生活中对于时间再熟悉不过了,但如果问你时间究竟是什么?仔细想想或许没那么简单。比如时间究竟是绝对的还是相对的呢?时间有没有起点和终点?时间流动的时候,是连续的?还是离散的呢?
当我们觉得时间只是一串简单的数字时,或许并不会想到这些复杂的问题,同样我们看到计算机上的时间数字,也无法感受其复杂的背后。
所以,本期我们就单纯的站在计算机的角度,来聊聊操作系统里的时间子系统模块。关于时间的维度
在说具体模块之前,先说说时间的维度。
其实我们始终对于时间有很强烈的需求,这种需求源于我们自身需要知道现在处于什么时间,以及如何描述一段时间,也就是时刻和时段的概念。
那我们所处的某一刻怎么描述?需要解决两个难点,一个是如何找到一个规律且实用的体系,一个是如何描述的精确。精确很重要,如果不能精确地描述时间,只说某个粗略的时间段,那么传递信息的偏差就会很大。
所以古人很早通过观察天象以及自然的变化规律,以地球自转和公转的周期去记录时间的流逝,比如中国古代会按照天干地支以60年为一个轮回去循环记录一年又一年,同时把1年分为数月,每月再分为若干天,每天再分为多少时辰,每个时辰又分几刻,这样基本上可以很清楚的体现地球运转的规律,同时也可以精确的描述时刻和时段,比如癸卯年七月初二卯时三刻。
而现如今我们则采用公元纪年法,相比之下精确到秒的维度,可以让时间更加精确,同时让更多的人处在同一个时间线之下。多个层级的时间维度包括:60秒=1分钟,60分钟=1小时,24小时=1天,365天=1年等;
对日常生活来说我们精确到秒已经足够了,但其实在科研中还需要更高的精度,于是便把1秒的1/1000叫1毫秒,1毫秒的1/1000叫做1微秒,1微秒的1/1000叫做1纳秒,用以更精确的表示时间。
那计算机中的时间是用什么维度表示呢?
其实相比人类常使用的多维度时间的表示,计算机只能处理单维度的时间表示。所以产生了个问题,那就是如果用秒作为基本单位,精度显然达不到,但如果用纳秒作为基本单位的话,数值又太大。所以计算机中的时间采用的是两层表示维度,超过1秒的时间用秒表示,不够一秒的时间用纳秒表示,每10亿纳秒向前进位一秒。这样计算机中时间处理就非常方便了。Linux内核中的时间
很多年前,大家都会在家里使用挂钟、座钟之类的查看时间,也包括日常佩戴的手表,但现如今很多人手表戴的也少了,更多的是用手机看时间,除此之外,手机还有计时,闹钟等功能。
而手机上的这些时间相关功能主要由计算机系统提供,我们把这些功能可以看成一个个的APP,比如安卓手机的时钟APP需要安卓操作系统(Linux内核)的支持,内核的时间子系统的实现也需要有相关硬件的支持。
下面介绍几个Linux kernel中和时间相关的基本概念
1、系统时钟(system clock)
时间就像是一条没有起点、没有终点的线段,除了要给出度量单位(例如秒),还要给出参考点。对于linux kernel而言,这个参考点就是Linux Epoch。
所谓linux Epoch其实就是1970年1月1日0点0分0秒(UTC)的时间点。虽然人类喜欢年、月、日、时、分、秒这些概念,不过对于计算机,更喜欢使用当前的时间点到linux epoch的秒数。一个符合POSIX标准的系统必须提供系统时钟,以不小于秒的精度来记录到linux epoch的时间值。
内核支持的system clock定义如下:
CLOCK_REALTIME是描述真实世界的时钟(这里的英文realtime有两个意思,一个表示真实的时间的意思,另外一个是实时性的意思,需要根据上下文判断,我们这个场景当然不是讲实时性),就类似挂在墙上的钟表一样,告知人类当前的时间。当然,家里的钟表你当然可以按照你的意愿向前或者向后调整。CLOCK_MONOTONIC是一个禁止人为设定的真实世界的时钟,你没有办法设定它,但是可以通过NTP协议进行调整。更多的system clock ID会在后续的文章中给出详细定义
2、 broken-down POSIX time
在time line上以linux epoch为参考点,用到参考点的秒数来表示timeline上的某个时间点的方法对于计算机而言当然是方便的,不过对于使用计算机的人类而言,我们更习惯broken-down time,也就是将那个冰冷的到参考点的秒数值分解成年月日时分秒。在内核中用下面的数据结构表示:
3、不同精度的时间表示
传统的unix使用了基于秒的时间定义,相关的数据结构是time_t:
time_t是POSIX标准定义的一个以秒计的时间值。例如大家都比较熟悉的time函数,可以获取一个从linux Epoch到当前时间点的秒值,该函数的返回值类型就是time_t的。如果time_t被实现成一个signed 32-bit integer,那么实际上在2038年的时候就会有溢出问题。
随着应用的发展,秒精度已经无法满足要求,因此出现了微秒精度的时间表示:
struct timeval 的概念和time_t是一样的,只不过多了一个微秒的成员,将时间的精度推进到微秒级别。在计算当前时刻到epoch时间点的微秒数值的时候可以使用公式:tv_sec x 10^6 + tv_usec。
由于实时应用程序的需求,POSIX标准最终将时间精度推进到纳秒,纳秒精度的时间表示如下:
根据POSIX标准,timeline上一个时间点的值用struct timespec来表示,它应该最少包括:
成员数据类型成员的名字
描述
time_t
tv_sec
该时间点上的秒值,仅在大于或者等于0的时候有效。
long
tv_nsec
该时间点上的ns值,仅在大于或者等于0,并且小于10^9纳秒的时候有效。
struct timespec和struct timeval概念类似,这里不再赘述。
部分内容转载自蜗窝科技
原文链接:http://www.wowotech.net/timer_subsystem/time_concept.html