计算机中的时间
寫在前面:時(shí)鐘可以說(shuō)是計(jì)算機(jī)的心臟,它是分時(shí)系統(tǒng)的基礎(chǔ)。如果時(shí)鐘反應(yīng)到應(yīng)用程序的層面,就是時(shí)間,很多應(yīng)用程序都會(huì)涉及到時(shí)間處理。本文就來(lái)討論一下計(jì)算機(jī)中的時(shí)鐘與時(shí)間。
1、操作系統(tǒng)中的時(shí)間
在Unix/Linux系統(tǒng)中,有兩個(gè)不同的時(shí)間:日歷時(shí)間和進(jìn)程時(shí)間。
(1)日歷時(shí)間:
有些書上又叫系統(tǒng)時(shí)間。該值是自1970年1月1日00:00:00以來(lái)國(guó)際標(biāo)準(zhǔn)時(shí)間(U T C)所經(jīng)過(guò)的秒數(shù)累計(jì)值(早期的手冊(cè)稱U T C為格林尼治標(biāo)準(zhǔn)時(shí)間)。在PC/AT微機(jī)系統(tǒng)中,支撐該時(shí)間的硬件是實(shí)時(shí)鐘RT(Real Time)電路。操作系統(tǒng)在系統(tǒng)初始化的過(guò)程中,會(huì)從該電路中讀取該時(shí)間,并保存在內(nèi)核變量中。
來(lái)看看Linux1.0中相關(guān)的代碼
extern?long?kernel_mktime(struct?mktime?*?time);
//初始化時(shí)間
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
//保存系統(tǒng)時(shí)間的內(nèi)核變量
volatile?struct?timeval?xtime;????????/*?The?current?time?*/
//linux/mktime.h
struct?mktime?{
????int?sec;??//秒
????int?min;??//分鐘
????int?hour;??//小時(shí)
????int?day;???//天
????int?mon;??//月
????int?year;??//年
};
//kernel/mktime.c
//計(jì)算1970年1月1日00:00:00以來(lái)秒的累計(jì)值
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)進(jìn)程時(shí)間
該時(shí)間用來(lái)度量進(jìn)程使用CPU的時(shí)間。
來(lái)看看Linux 1.0中相應(yīng)的代碼:
//內(nèi)核任務(wù)的結(jié)構(gòu)定義
struct?task_struct{
//…
//依次為:用戶CPU時(shí)間,系統(tǒng)CPU時(shí)間,子進(jìn)程用戶CPU時(shí)間,子進(jìn)程系統(tǒng)CPU時(shí)間,
//進(jìn)程開始運(yùn)行時(shí)間
long?utime,stime,cutime,cstime,start_time;?
//…
}
?當(dāng)度量一個(gè)進(jìn)程的執(zhí)行時(shí)間時(shí),Unix系統(tǒng)使用三個(gè)進(jìn)程時(shí)間值:
? 時(shí)鐘時(shí)間。
? 用戶C P U時(shí)間。
? 系統(tǒng)C P U時(shí)間。
要取得任一進(jìn)程的時(shí)鐘時(shí)間、用戶時(shí)間和系統(tǒng)時(shí)間很容易——只要執(zhí)行命令 t i m e ( 1 ),其參數(shù)是要度量其執(zhí)行時(shí)間的命令,例如:
$ 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有關(guān)。
該時(shí)間的支撐硬件在PC機(jī)中是可編程定時(shí)芯片Intel8253(8254)。8254芯片的時(shí)鐘輸入頻率是1193180,我們通過(guò)設(shè)定一定的初始計(jì)數(shù)值(LATCH),默認(rèn)值為65535,就能控制該芯片的輸出頻率,默認(rèn)為1193180/65535hz,例如,假定LATCH=1193180/100,我們就能保證輸出頻率為100hz,即周期為10ms,我們稱為系統(tǒng)的時(shí)鐘周期,或者1個(gè)系統(tǒng)滴答。這樣,1個(gè)系統(tǒng)的滴答就為10ms,這也Linux的默認(rèn)值。
8254芯片每經(jīng)過(guò)一個(gè)滴答時(shí)間,就會(huì)向CPU發(fā)出一個(gè)時(shí)鐘中斷。Linux會(huì)在時(shí)鐘中斷處理過(guò)程增加內(nèi)核變量jiffies值,該值累計(jì)系統(tǒng)開機(jī)以來(lái)的經(jīng)過(guò)的時(shí)鐘滴答數(shù)。
Linux 1.0中的代碼:
unsigned?long?volatile?jiffies=0;?//累計(jì)系統(tǒng)開機(jī)以來(lái)的滴答數(shù)
2、標(biāo)準(zhǔn)C庫(kù)中的時(shí)間函數(shù)
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函數(shù)返回當(dāng)前進(jìn)程的使用處理器的時(shí)間的近似值,每秒的的時(shí)鐘滴答數(shù)用宏CLOCKS_PER_SEC定義。
在傳統(tǒng)的C語(yǔ)言中,clock函數(shù)返回的類型為long(如上),但返回值實(shí)際上為unsigned long類型,long是在C語(yǔ)言加入unsigned long之前使用的。計(jì)算處理器時(shí)間總是使用無(wú)符號(hào)數(shù)算術(shù)。一些非標(biāo)準(zhǔn)實(shí)現(xiàn)中使用times函數(shù),而不是clock函數(shù),其返回的結(jié)構(gòu)化值報(bào)告處理器時(shí)間的各個(gè)成員,通常以1/60秒為單位。如下:
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));
標(biāo)準(zhǔn)C中函數(shù)time返回當(dāng)前的日歷時(shí)間,返回值類型為time_t。
/time.hextern?char?*asctime?__P?((__const?struct?tm?*__tp));
/*?Equivalent?to?`asctime?(localtime?(timer))'.??*/
extern?char?*ctime?__P?((__const?time_t?*__timer));
?這兩個(gè)函數(shù)都返回時(shí)間的字符串的形式。
//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將日歷時(shí)間轉(zhuǎn)換成stuct tm類型的分解形式,只不過(guò)前者轉(zhuǎn)換成GMT時(shí)間,而后者轉(zhuǎn)換成本地時(shí)間。
?
轉(zhuǎn)載于:https://www.cnblogs.com/hustcat/archive/2009/06/14/1503244.html
總結(jié)
- 上一篇: Vczh Library++ 语法分析器
- 下一篇: SSIS包如何动态指定文件路径