博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

linux时间相关结构体和函数整理

Posted on 2016-03-31 10:20  bw_0927  阅读(1602)  评论(0编辑  收藏  举报

http://blog.chinaunix.net/uid-14617649-id-3058661.html

http://blog.csdn.net/droidphone/article/details/7989566

 

 

time -p ./main  
使用一个核
real 1.92	// 程序开始到结束时间差 (  CPU 时间)
user 3.80	// 用户态所使用 CPU 时间 (多核累加) 
sys 0.01	// 内核态所使用 CPU 时间片结果:
使用两个核
real         1.89
user         3.76	// 虽然总时间差不多,但由 2 个核并行,real 时间自然少了许多。 
sys          0.00

 

1.  时间的种类

内核管理着多种时间,它们分别是:

 

  • RTC时间
  • wall time:墙上时间
  • monotonic time
  • raw monotonic time
  • boot time:总启动时间

 

RTC时间  在PC中,RTC时间又叫CMOS时间,它通常由一个专门的计时硬件来实现,软件可以读取该硬件来获得年月日、时分秒等时间信息,而在嵌入式系统中,有使用专门的RTC芯片,也有直接把RTC集成到Soc芯片中,读取Soc中的某个寄存器即可获取当前时间信息。一般来说,RTC是一种可持续计时的,也就是说,不管系统是否上电,RTC中的时间信息都不会丢失,计时会一直持续进行,硬件上通常使用一个后备电池对RTC硬件进行单独的供电。因为RTC硬件的多样性,开发者需要为每种RTC时钟硬件提供相应的驱动程序,内核和用户空间通过驱动程序访问RTC硬件来获取或设置时间信息。

xtime  xtime和RTC时间一样,都是人们日常所使用的墙上时间,只是RTC时间的精度通常比较低,大多数情况下只能达到毫秒级别的精度,如果是使用外部的RTC芯片,访问速度也比较慢,为此,内核维护了另外一个wall time时间:xtime,取决于用于对xtime计时的clocksource,它的精度甚至可以达到纳秒级别,因为xtime实际上是一个内存中的变量,它的访问速度非常快,内核大部分时间都是使用xtime来获得当前时间信息。xtime记录的是自1970年1月1日24时到当前时刻所经历的纳秒数。

monotonic time  该时间自系统开机后就一直单调地增加,它不像xtime可以因用户的调整时间而产生跳变,不过该时间不计算系统休眠的时间,也就是说,系统休眠时,monotoic时间不会递增。

raw monotonic time  该时间与monotonic时间类似,也是单调递增的时间,唯一的不同是:raw monotonic time“更纯净”,他不会受到NTP时间调整的影响,它代表着系统独立时钟硬件对时间的统计。

boot time  与monotonic时间相同,不过会累加上系统休眠的时间,它代表着系统上电后的总时间。

 

 

时间种类 精度(统计单位) 访问速度 累计休眠时间 受NTP调整的影响
RTC Yes Yes
xtime Yes Yes
monotonic No Yes
raw monotonic No No
boot time Yes Yes

 

一、时间类型。Linux下常用的时间类型有4个:time_t,struct timeb, struct timeval,struct timespec,clock_t, struct tm.

  • (1) time_t是一个长整型,一般用来表示用1970年以来的秒数.

该类型定义在中.

一般通过 time_t time = time(NULL); 获取.    //秒

 

  • (2) struct timeb结构: 主要有两个成员, 一个是秒, 另一个是毫秒, 精确度为毫秒.

 

  1. struct timeb
  2. {
  3.     time_t time;
  4.     unsigned short millitm;   //毫秒
  5.     short timezone;
  6.     short dstflag;
  7. };

 

由函数int ftime(struct timeb *tp); 来获取timeb.

成功返回0, 失败返回-1.

 

  • (3) struct timeval有两个成员,一个是秒,一个是微妙.

 

  1. struct timeval 
  2. {
  3.     long tv_sec; /* seconds */
  4.     long tv_usec; /* microseconds */.  微秒
  5. };
由int gettimeofday(struct timeval *tv, struct timezone *tz);获取.
struct timezone结构的定义为:
 
  1. struct timezone
  2. {
  3.    int tz_minuteswest; /* 和Greewich时间差了多少分钟*/
  4.    int tz_dsttime; /* 日光节约时间的状态 */
  5. };

 

  • (4) struct timespec有两个成员,一个是秒,一个是纳秒, 所以最高精确度是纳秒.
  1. struct timespec
  2. {
  3.     time_t tv_sec; /* seconds */
  4.     long tv_nsec; /* nanoseconds */  //纳秒
  5. };
一般由函数long clock_gettime (clockid_t which_clock, struct timespec *tp); 获取.
获取特定时钟的时间,时间通过tp结构传回,目前定义了6种时钟,分别是

   CLOCK_REALTIME                统当前时间,从1970年1.1日算起

   CLOCK_MONOTONIC               系统的启动时间,不能被设置

   CLOCK_PROCESS_CPUTIME_ID      进程运行时间

   CLOCK_THREAD_CPUTIME_ID       线程运行时间

   CLOCK_REALTIME_HR             CLOCK_REALTIME的高精度版本

   CLOCK_MONOTONIC_HR            CLOCK_MONOTONIC的高精度版本

   获取特定时钟的时间精度:

   long clock_getres(clockid_t );

   设置特定时钟的时间:

   long clock_settime(clockid_t ,struct timespec*);

   休眠time中指定的时间,如果遇到信号中断而提前返回,则由left_time返回剩余的时间:

   long clock_nanosleep(clockid_t ,int flag,timespec* time,timespec* left_time);

 

Middleware对POSIX提供的标准计时器API进行封装,主要提供了两种类型的时钟的封装。一种是CLOCK_REALTIME,另一种是CLOCK_MONOTONIC。对与man手册的解释是:
CLOCK_REALTIME: Systemwide realtime clock. 系统范围内的实时时钟。
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set. 表示单调时间,不能被设置的。

手册中解释的比较笼统。我个人的理解是:
CLOCK_REALTIME:这种类型的时钟可以反映wall clock time,用的是绝对时间,当系统的时钟源被改变,或者系统管理员重置了系统时间之后,这种类型的时钟可以
得到相应的调整,也就是说,系统时间影响这种类型的timer
CLOCK_MONOTONIC:用的是相对时间,他的时间是通过jiffies值来计算的。该时钟不受系统时钟源的影响,只受jiffies值的影响

建议使用:
CLOCK_MONOTONIC这种时钟更加稳定,不受系统时钟的影响。如果想反映wall clock time,就使用CLOCK_REALTIME。

 

 

 

  • (5) clock_t类型, 由clock_t clock(); 返回获取.

表示进程占用的cpu时间. 精确到微秒.

 

  • (6) struct tm是直观意义上的时间表示方法:

 

  1. struct tm 
  2. {
  3.     int tm_sec; /* seconds */
  4.     int tm_min; /* minutes */
  5.     int tm_hour; /* hours */
  6.     int tm_mday; /* day of the month */
  7.     int tm_mon; /* month */
  8.     int tm_year; /* year */
  9.     int tm_wday; /* day of the week */
  10.     int tm_yday; /* day in the year */
  11.     int tm_isdst; /* daylight saving time */
  12. };
struct tm* gmtime(const time_t *timep);
struct tm* localtime(const time_t *timep);
time_t mktime(struct tm *tm);
gmtime和localtime的参数以及返回值类型相同,区别是前者返回的格林威治标准时间,后者是当地时间.
注意: 这边三个函数都是线程不安全的, 要使用线程安全的版本, 需要使用带_r的版本 -- gmtime_r, localtime_r, mktime_r.
 
 
二、 延迟函数
主要的延迟函数有:sleep(),usleep(),nanosleep(),select(),pselect().
 
  1. unsigned int sleep(unsigned int seconds);
  2. void usleep(unsigned long usec);
  3. int nanosleep(const struct timespec *req, struct timespec *rem);
  4. int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout);
  5. int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);
alarm函数是信号方式的延迟,这种方式不直观,这里不说了。

仅通过函数原型中时间参数类型,可以猜测sleep可以精确到秒级,usleep/select可以精确到微妙级,nanosleep和pselect可以精确到纳秒级


而实际实现中,linux上的nanosleep和alarm相同,都是基于内核时钟机制实现,受linux内核时钟实现的影响,并不能达到纳秒级的精度,man nanosleep也可以看到这个说明,man里给出的精度是:Linux/i386上是10 ms ,Linux/Alpha上是1ms。