计算机中的时间

写在前面:时钟可以说是计算机的心脏,它是分时系统的基础。如果时钟反应到应用程序的层面,就是时间,很多应用程序都会涉及到时间处理。本文就来讨论一下计算机中的时钟与时间。

1、操作系统中的时间
在Unix/Linux系统中,有两个不同的时间:日历时间和进程时间。
(1)日历时间:
有些书上又叫系统时间。该值是自1970年1月1日00:00:00以来国际标准时间(U T C)所经过的秒数累计值(早期的手册称U T C为格林尼治标准时间)。在PC/AT微机系统中,支撑该时间的硬件是实时钟RT(Real Time)电路。操作系统在系统初始化的过程中,会从该电路中读取该时间,并保存在内核变量中。
来看看Linux1.0中相关的代码

// kernel/time.c
extern   long  kernel_mktime( struct  mktime  *  time);
// 初始化时间
void  time_init( void )
{
    
struct  mktime time;
    
int  i;

    
/*  checking for Update-In-Progress could be done more elegantly
     * (using the "update finished"-interrupt for example), but that
     * would require excessive testing. promise I'll do that when I find
     * the time.            - Torsten
     
*/
    
/*  read RTC exactly on falling edge of update flag  */
    
for  (i  =   0  ; i  <   1000000  ; i ++ )     /*  may take up to 1 second  */
        
if  (CMOS_READ(RTC_FREQ_SELECT)  &  RTC_UIP)
            
break ;
    
for  (i  =   0  ; i  <   1000000  ; i ++ )     /*  must try at least 2.228 ms */
        
if  ( ! (CMOS_READ(RTC_FREQ_SELECT)  &  RTC_UIP))
            
break ;
    
do  {  /*  Isn't this overkill ? UIP above should guarantee consistency  */
        time.sec 
=  CMOS_READ(RTC_SECONDS);
        time.min 
=  CMOS_READ(RTC_MINUTES);
        time.hour 
=  CMOS_READ(RTC_HOURS);
        time.day 
=  CMOS_READ(RTC_DAY_OF_MONTH);
        time.mon 
=  CMOS_READ(RTC_MONTH);
        time.year 
=  CMOS_READ(RTC_YEAR);
    } 
while  (time.sec  !=  CMOS_READ(RTC_SECONDS));
    
if  ( ! (CMOS_READ(RTC_CONTROL)  &  RTC_DM_BINARY)  ||  RTC_ALWAYS_BCD)
      {
        BCD_TO_BIN(time.sec);
        BCD_TO_BIN(time.min);
        BCD_TO_BIN(time.hour);
        BCD_TO_BIN(time.day);
        BCD_TO_BIN(time.mon);
        BCD_TO_BIN(time.year);
      }
    time.mon
-- ;
    xtime.tv_sec 
=  kernel_mktime( & time);
}


// kernel/sched.c
// 保存系统时间的内核变量
volatile   struct  timeval xtime;         /*  The current time  */

// linux/mktime.h
struct  mktime {
    
int  sec;   //
     int  min;   // 分钟
     int  hour;   // 小时
     int  day;    //
     int  mon;   //
     int  year;   //
};
// kernel/mktime.c
// 计算1970年1月1日00:00:00以来秒的累计值
long  kernel_mktime( struct  mktime  *  time)
{
    
long  res;
    
int  year;

    year 
=  time -> year  -   70 ;
/*  magic offsets (y+1) needed to get leapyears right. */
    res 
=  YEAR * year  +  DAY * ((year + 1 ) / 4 );
    res 
+=  month[time -> mon];
/*  and (y+2) here. If it wasn't a leap-year, we have to adjust  */
    
if  (time -> mon > 1   &&  ((year + 2 ) % 4 ))
        res 
-=  DAY;
    res 
+=  DAY * (time -> day - 1 );
    res 
+=  HOUR * time -> hour;
    res 
+=  MINUTE * time -> min;
    res 
+=  time -> sec;
    
return  res;
}

// linux/time.h
struct  timeval {
    
long     tv_sec;         /*  seconds  */
    
long     tv_usec;     /*  microseconds  */
};

(2)进程时间
该时间用来度量进程使用CPU的时间。
来看看Linux 1.0中相应的代码:

// linux/sched.h
// 内核任务的结构定义
struct  task_struct{
//
// 依次为:用户CPU时间,系统CPU时间,子进程用户CPU时间,子进程系统CPU时间,
// 进程开始运行时间
long  utime,stime,cutime,cstime,start_time; 
//
}

 当度量一个进程的执行时间时,Unix系统使用三个进程时间值:
• 时钟时间。
• 用户C P U时间。
• 系统C P U时间。
要取得任一进程的时钟时间、用户时间和系统时间很容易——只要执行命令 t i m e ( 1 ),其参数是要度量其执行时间的命令,例如:
$ cd /usr/include
$ time grep _POSIX_SOURCE */*.h > /dev/null
real   0m19.81s
user   0m0.43s
sys    0m4.53s
t i m e命令的输出格式与所使用的s h e l l有关。

该时间的支撑硬件在PC机中是可编程定时芯片Intel8253(8254)。8254芯片的时钟输入频率是1193180,我们通过设定一定的初始计数值(LATCH),默认值为65535,就能控制该芯片的输出频率,默认为1193180/65535hz,例如,假定LATCH=1193180/100,我们就能保证输出频率为100hz,即周期为10ms,我们称为系统的时钟周期,或者1个系统滴答。这样,1个系统的滴答就为10ms,这也Linux的默认值。
8254芯片每经过一个滴答时间,就会向CPU发出一个时钟中断。Linux会在时钟中断处理过程增加内核变量jiffies值,该值累计系统开机以来的经过的时钟滴答数。

Linux 1.0中的代码:

// kernel/sched.c
unsigned  long   volatile  jiffies = 0 // 累计系统开机以来的滴答数

2、标准C库中的时间函数

typedef  long   int  __clock_t;     /*  Type of CPU usage counts.   */
typedef 
long   int  __time_t;


// time.h
typedef __clock_t clock_t;
#define  CLOCKS_PER_SEC  …
typedef __time_t time_t;

extern  clock_t clock __P (( void ));
extern  time_t time __P ((time_t  * __timer));

 clock函数返回当前进程的使用处理器的时间的近似值,每秒的的时钟滴答数用宏CLOCKS_PER_SEC定义。
在传统的C语言中,clock函数返回的类型为long(如上),但返回值实际上为unsigned long类型,long是在C语言加入unsigned long之前使用的。计算处理器时间总是使用无符号数算术。一些非标准实现中使用times函数,而不是clock函数,其返回的结构化值报告处理器时间的各个成员,通常以1/60秒为单位。如下:

// sys/times.h
struct  tms
  {
    clock_t tms_utime;        
/*  User CPU time.   */
    clock_t tms_stime;        
/*  System CPU time.   */

    clock_t tms_cutime;        
/*  User CPU time of dead children.   */
    clock_t tms_cstime;        
/*  System CPU time of dead children.   */
  };


/*  Store the CPU time used by this process and all its
   dead children (and their dead children) in BUFFER.
   Return the elapsed real time, or (clock_t) -1 for errors.
   All times are in CLK_TCKths of a second.  
*/
extern  clock_t times __P (( struct  tms  * __buffer));

标准C中函数time返回当前的日历时间,返回值类型为time_t。

/ time.h
extern   char   * asctime __P ((__const  struct  tm  * __tp));

/*  Equivalent to `asctime (localtime (timer))'.   */
extern   char   * ctime __P ((__const time_t  * __timer));

 这两个函数都返回时间的字符串的形式。

// time.h

/*  Return the `struct tm' representation of *TIMER
   in Universal Coordinated Time (aka Greenwich Mean Time).  
*/
extern   struct  tm  * gmtime __P ((__const time_t  * __timer));

/*  Return the `struct tm' representation
   of *TIMER in the local timezone.  
*/
extern   struct  tm  * localtime __P ((__const time_t  * __timer));

/*  Used by other time functions.   */
struct  tm
{
  
int  tm_sec;             /*  Seconds.    [0-60] (1 leap second)  */
  
int  tm_min;             /*  Minutes.    [0-59]  */
  
int  tm_hour;             /*  Hours.    [0-23]  */
  
int  tm_mday;             /*  Day.        [1-31]  */
  
int  tm_mon;             /*  Month.    [0-11]  */
  
int  tm_year;             /*  Year    - 1900.   */
  
int  tm_wday;             /*  Day of week.    [0-6]  */
  
int  tm_yday;             /*  Days in year.[0-365]     */
  
int  tm_isdst;             /*  DST.        [-1/0/1] */

#ifdef    __USE_BSD
  
long   int  tm_gmtoff;         /*  Seconds east of UTC.   */
  __const 
char   * tm_zone;     /*  Timezone abbreviation.   */
#else
  
long   int  __tm_gmtoff;         /*  Seconds east of UTC.   */
  __const 
char   * __tm_zone;     /*  Timezone abbreviation.   */
#endif
};

 gmtime与localtime将日历时间转换成stuct tm类型的分解形式,只不过前者转换成GMT时间,而后者转换成本地时间。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值