您的位置:首页 > 运维架构 > Linux

C/C++:Linux时间函数以及基本概念

2017-10-29 22:14 435 查看

C/C++:Linux时间函数以及基本概念

1秒(s)=10^3毫秒(ms);
1毫秒(ms)=10^3微秒(us);
1微秒(us)=10^3纳秒(ns);


NAME
time - get time in seconds
SYNOPSIS
#include <time.h>
time_t time(time_t *t);
DESCRIPTION
time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
If t is non-NULL, the return value is also stored in the memory pointed to by t.
RETURN VALUE
On success, the value of time in seconds since the Epoch is returned.  On error, ((time_t) -1) is returned, and errno is set appropriately.


其余更多资料可以执行”man 2 time”来查看

#include <iostream>
#include <time.h>

using namespace std;

int main()
{
time_t now;
time(&now);
cout<<now<<endl;
return 0;
}


time是个系统函数,其功能是返回当前系统时间(Wall Time),自1970-01-01 00:00:00开始所经历的秒数。

注意,time函数的精度是秒,变量类型时time_t。

NAME
gettimeofday, settimeofday - get / set time<
e545
/span>
SYNOPSIS
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
DESCRIPTION
The  functions  gettimeofday()  and  settimeofday()  can  get  and  set  the  time  as well as a timezone.
The tv argument is a struct timeval (as specified in <sys/time.h>):
struct timeval {
time_t      tv_sec;     /* seconds */
suseconds_t tv_usec;    /* microseconds */
};
The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL.
RETURN VALUE
gettimeofday() and settimeofday() return 0 for success, or -1 for failure (in which case errno is set appropriately).


其余更多资料可以执行”man 2 gettimeofday”来查看

#include <iostream>
#include <sys/time.h>

using namespace std;

int main()
{
struct timeval now;
gettimeofday(&now, NULL);
cout<<"sec : "<<now.tv_sec<<endl;
cout<<"usec: "<<now.tv_usec<<endl;
return 0;
}


gettimeofday类似time函数,也是一个系统函数;

其功能是返回当前系统时间(Wall Time),自1970-01-01 00:00:00开始所经历的秒数以及微秒数。

注意,参数类型是个结构体,包含两部分:

一部分是tv_sec,代表秒数;

一部分是tv_usec,代表微秒数;

即,gettimeofday精度是微秒级别的;

还有个注意的地方,时区tz一般都置NULL。

NAME
clock_gettime
SYNOPSIS
#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);
Link with -lrt (only for glibc versions before 2.17).
DESCRIPTION
The functions clock_gettime() and clock_settime() retrieve and set the time of the specified clock clk_id.
The res and tp arguments are timespec structures, as specified in <time.h>:
struct timespec {
time_t   tv_sec;        /* seconds */
long     tv_nsec;       /* nanoseconds */
};
The  clk_id  argument is the identifier of the particular clock on which to act.  A clock may be system-wide and hence visible for all processes, or per-process if it measures time only within a single process.
clk_id:
CLOCK_REALTIME
CLOCK_MONOTONIC
……


其余更多资料可以执行”man 2 clock_gettime”来查看

clock_gettime如同time、gettimeofday一样是个系统函数;

其通过clk_id来指定不同的时钟(例如REALTIME或者MONOTONIC),以获取不同的时间值;

其参数是个结构体:

一部分是tv_sec,代表秒数;

一部分是tv_nsec,代表纳秒数;

我常用的有两个:

CLOCK_REALTIME:返回当前系统时间(Wall Time),自1970-01-01 00:00:00开始所经历的秒数以及纳秒数;

CLOCK_MONOTONIC:这个是个特殊的单调时钟源,后续再说。

注意下,通常CLOCK_REALTIME是都支持的,但是其余的clk_id就不一定支持了。

就CLOCK_MONOTONIC来说,在Linux/IBM-AIX上我试了下应该都支持,但是在HPUX上就不支持,其仅仅支持CLOCK_REALTIME。

此函数精度为纳秒级别。

============================分割线==============================

我上面曾经指明:

time函数以及gettimeofday,返回的值代表的都是系统时间。

啥是系统时间?

系统时间是自1970-01-01 00:00:00开始的时间。

很奇怪是不是?为啥是从某个时间点开始经历的时间呢?

因为要量化时间,必须以某一个时间点作为参照,然后才能说:

距离XXX时间点走过多少秒、毫秒、微秒、纳秒。

通常在计算机操作系统中存在两个时间:

1.系统时间;

2.硬件时间;

我们先想个问题:

计算机在断电时,RAM是没有电的,无法维持存在于RAM中的数据;

那当计算机开机时,运行操作系统,操作系统显示的当前时间点的数值是怎么的出来的呢?

可能是从网络中某个时间服务器通过类似NTP方式同步的?

但是我们在没有网络连接的情况下,似乎也可以呀?

当计算机关机时,你可以将当前时间记录在某个文件中,下次启动OS时读取,但是在重启的期间,可没有一个定时器帮你记录走过多少时间,OS是不知道的噢!

在主板上有个特殊的芯片,就是CMOS。

CMOS是微机主板上的一块可读写的RAM芯片,主要用来保存当前系统的硬件配置和操作人员对某些参数的设定。

CMOS RAM芯片由系统通过一块后备电池供电,因此无论是在关机状态中,还是遇到系统掉电情况,CMOS信息都不会丢失。

注:以上部分关于CMOS内容摘自百度知道回答

是的,我们的硬件时钟的值就是记录在CMOS中的,当计算机关机状态下,实际还有一个小的电池在供电,维持着一些参数,其中就包含了硬件时间。

So,我们的硬件时间是不会丢失啦。

那么和系统时间有啥关系?

因为系统时间是在开机时,自动从CMOS中读取硬件时间作为自己的值的。

一切真相大白了!

系统时间只有在一开始的那一刻,是和硬件时间同步一致的,但是后续,这个系统时间是维持在系统内核当中的值,与硬件时间没关系啦,完全是两个不同的时间源,所以二者可能会有一定的“漂移”(或者通俗点叫做时间偏差)。

我们通常在Linux下使用的命令和函数:

[test1280@localhost 20171029]$ date
Sun Oct 29 06:29:52 PDT 2017


time
gettimeofday
clock_gettime(CLOCK_REALTIME...)


获取的都是这个系统时间值,由内核维持着的。

噢,再多加一句:硬件时间(Hardware Clock),别名叫做RTC时间,Real Time Clock。

再深入一些:

在Linux的时钟中断中涉及两个全局变量:

1.xtime

2.jiffies

xtime就是我们的系统时间,系统boot时从CMOS中读取硬件时间作为自己的值;

jiffies是记录着系统boot后到现在总共的时钟中断次数;

jiffies取决于系统的频率,单位是Hz;

Linux系统时钟频率是一个常数HZ来决定的,通常HZ=100,那么他的精度度就是10ms。

也就是说每10ms一次中断。所以一般来说Linux的精确度是10毫秒。

Linux内核从2.5版内核开始把频率从100调高到1000。

在 Linux 2.6 中,系统时钟每 1 毫秒中断一次(时钟频率,用 HZ 宏表示,定义为 1000,即每秒中断 1000次,2.4 中定义为 100,很多应用程序也仍然沿用 100 的时钟频率),这个时间单位称为一个 jiffie。

当知道jiffies的值后,完全可以计算出自系统boot后的时间(jiffies在boot时初始化为0),因为知道系统时钟频率嘛~

jiffies定义:

extern unsigned long volatile jiffies;


嗯,一个unsigned long类型的变量,大家可以算算jiffies多长时间之内不会溢出?

是很长的一个时间,我的有生之年是看不到它溢出了…

(PS:x86的32bit机器是否会溢出?嗯,有相关宏来保证的,放心吧…)

其他:

tick是HZ的倒数,意即Timer Interrupt每发生一次中断的时间。

如HZ为250时,tick则为4ms。

每过一个tick的时间,jiffies就单调递增1(单调递增,指的是不会也不能将时间设置到一个小的数字,不可逆,严格递增)。

我们的CLOCK_MONOTONIC则是通过读取jiffies中的值来计算当前系统已经启动多长时间啦。

xtime(系统时间)和jiffies都是操作系统内核在维持着的两个变量,存在于内存中;

xtime是可以被更改的,向前或者向后,这时,依赖于xtime的所有函数、命令都会相应的改变。

举个例子:
当你pthread_cond_timedwait的abstime是当前时间点的60*60s(即1h)之后,如果你立刻使用date设置系统时间调到1h之后,那么pthread_cond_timedwait会立刻从阻塞中超时返回...


而jiffies是不会更改的。

所以使用CLOCK_MONOTONIC,即使你如何设置xtime,如何使用date来更改系统时间,都不会影响到CLOCK_MONOTONIC的时间的值的。

嗯,再总结下:

CLOCK_REALTIME是走的Wall Time,即系统时间,即xtime的时间;

CLOCK_MONOTONIC是走的另一个时间源:jiffies;

共同点就是xtime/jiffies都是由内核维持着的,断电之后其不存在~随OS存在而存在。

可以用类似hwclock的命令将xtime于RTC硬件时间相互同步(将当前xtime写回到CMOS中;从CMOS中读取时间到xtime中)。

还有个问题,CMOS中已经有了变量来记录时间,操作系统还要自己搞一个系统时间来呢?

这不是冗余嘛,坏处很大的呀?

首先有一个确定的有点:快。

从内存RAM中读取变量信息,当然比从CMOS上读取快呀!

其次,不太敢确定的一个原因:

因为CMOS上精度低,只是到了微秒级;

但是内核的系统时间精度高,到了纳秒级;

额,第二个原因不保证对哈!!!不一定对哈!!!

Refs:

1.http://blog.csdn.net/allen6268198/article/details/7270194

2.http://blog.csdn.net/google0802/article/details/53446013

3.http://blog.csdn.net/tangchenchan/article/details/47989473

我的其他关于CLOCK_MONOTONIC的文章

O(∩_∩)O:我写的比较杂乱一些,大家伙凑活着看看吧~

如有错误还请提出哈~

共同进步,不断学习,不断努力!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐