Linux時間編程

一塘幅、Linux時間類型

在Linux系統(tǒng)當(dāng)中,時間分為兩種類型:格林威治時間和日歷時間尿贫。

Coordinated Universal Time(UTC)是世界標(biāo)準(zhǔn)的時間电媳,即常說的格林威治標(biāo)準(zhǔn)時間(Greenwich Mean Time,GMT)庆亡;UTC與GMT兩者幾乎是同一概念匾乓,都是指格林威治時間,只不過UTC的稱呼更為正式一點(diǎn)又谋。兩者的區(qū)別是UTC是天文學(xué)上的概念拼缝,而GMT是基于一個原子鐘娱局。

Calendar Time是用“一個標(biāo)準(zhǔn)時間點(diǎn)(如1970年1月1日0點(diǎn))到此時經(jīng)過的秒數(shù)”來表示的時間,即日歷時間咧七;它與格林威治時間不同衰齐。

GMT是中央市區(qū),北京在東8區(qū)继阻,相差8個小時耻涛,所以北京時間=GMT時間+8小時。

++獲取系統(tǒng)時間函數(shù)有:time()瘟檩、gettimeofday()抹缕;++

++設(shè)置系統(tǒng)時間函數(shù)有:stime()、settimeofday()芒帕;++

二歉嗓、Linux時間格式

2.1 time_t 時間類型

time_t類型定義在time.h中:

#ifndef __TIME_T
#define __TIME_T
typedef long time_t
#endif

可見丰介,time_t實(shí)際是一個長整型背蟆。其值表示為從UTC(coordinated universal time)時間1970年1月1日00時00分00秒(也稱為Linux系統(tǒng)的Epoch時間)到當(dāng)前時刻的秒數(shù)。由于time_t類型長度的限制哮幢,它所表示的時間不能晚于2038年1月19日03時14分07秒(UTC)带膀。為了能夠表示更久遠(yuǎn)的時間,可用64位或更長的整型數(shù)來保存日歷時間橙垢。

time_t類型的時間可以通過time()函數(shù)獲取垛叨。

2.2 struct tm時間類型

struct tm結(jié)構(gòu)在time.h中定義為:

#include <time.h>
struct tm {
        int tm_sec;         /* seconds */
        int tm_min;         /* minutes */
        int tm_hour;        /* hours */
        int tm_mday;        /* day of the month */
        int tm_mon;         /* month */
        int tm_year;        /* year */
        int tm_wday;        /* day of the week */
        int tm_yday;        /* day in the year */
        int tm_isdst;       /* daylight saving time */
};

ANSI C標(biāo)準(zhǔn)稱使用tm結(jié)構(gòu)的這種時間為分解時間(broken-down time)。其成員介紹如下:

  • tm_sec:秒柜某,取值區(qū)間為[0嗽元,59];
  • tm_min:分喂击,取值區(qū)間為[0剂癌,59];
  • tm_hour:時翰绊,取值區(qū)間為[0佩谷,23];
  • tm_mday:日期监嗜,取值區(qū)間為[1谐檀,31];
  • tm_mon:月份裁奇,取值區(qū)間為[0桐猬,11];
  • tm_year:年份刽肠,其值為1900年至今的年數(shù)课幕;
  • tm_wday:星期厦坛,取值區(qū)間為[0,6]乍惊,0代表星期天杜秸,1代表星期一,以次類推润绎;
  • tm_yday:從年的1月1日開始的天數(shù)撬碟,取值區(qū)間為[0,365]莉撇,0代表1月1日呢蛤;
  • tm_isdst:夏令時標(biāo)識符,使用夏令時棍郎,tm_isdst為正其障;不使用夏令時,tm_isdst為0涂佃;不了解情況時励翼,tm_isdst為負(fù)。

使用gmtime()和localtime()可將time_t時間類型轉(zhuǎn)換為struct tm結(jié)構(gòu)體辜荠;

使用mktime()可將struct tm結(jié)構(gòu)體轉(zhuǎn)換為time_t時間類型汽抚;

使用asctime()將struct tm轉(zhuǎn)換為字符串形式。

2.3 struct timeval時間類型

struct timeval結(jié)構(gòu)體在sys/time.h中定義如下:

#include <sys/time.h>
struct timeval {
    time_t      tv_sec;     /* seconds:秒 */
    suseconds_t tv_usec;    /* microseconds:微妙 */
};

tv_sec是time_t時間類型伯病,其值也表示為從UTC(coordinated universal time)時間1970年1月1日00時00分00秒(也稱為Linux系統(tǒng)的Epoch時間)到當(dāng)期時刻的秒數(shù)造烁。

設(shè)置時間函數(shù)settimeofday()與獲取時間函數(shù)gettimeofday()均使用該事件類型作為參數(shù)傳遞。

2.4 struct timespec時間類型

struct timespec結(jié)構(gòu)體在time.h中定義為:

typedef long time_t;
struct timespec {
    time_t   tv_sec;     /* seconds:秒 */
    long     tv_nsec;    /* microseconds:納妙 */
};

它是POSIX.4標(biāo)準(zhǔn)定義的時間結(jié)構(gòu)午笛,精確度到納秒惭蟋,一般由clock_gettime(clockid_t, struct timespec *)獲取特定時鐘的時間。常用如下4種時鐘:

  • CLOCK_REALTIME 統(tǒng)當(dāng)前時間药磺,從1970年1.1日算起
  • CLOCK_MONOTONIC 系統(tǒng)的啟動時間告组,不能被設(shè)置
  • CLOCK_PROCESS_CPUTIME_ID 本進(jìn)程運(yùn)行時間
  • CLOCK_THREAD_CPUTIME_ID 本線程運(yùn)行時間

三、Linux時間編程接口

接下來介紹的時間編程函數(shù)接口均屬于Linux系統(tǒng)調(diào)用函數(shù)与涡。

3.1 time()函數(shù)

【函數(shù)原型】:

#include <time.h>
time_t time(time_t *tloc);

【函數(shù)說明】:

該函數(shù)用于獲取日歷時間惹谐,即從1970年1月1日0點(diǎn)到現(xiàn)在所經(jīng)歷的秒數(shù)。參數(shù)tloc通常設(shè)置為NULL驼卖,若tloc非空氨肌,time()函數(shù)也會將返回值存到tloc指針指向的內(nèi)存中。

【返回值】:

該函數(shù)執(zhí)行成功返回秒數(shù)酌畜,失敗則返回((time_t)-1)值怎囚,錯誤原因存于errno中。

【使用例程】:

#include <stdio.h>
#include <time.h>
    
int main(void)
{
    time_t seconds = 0;
    
    seconds = time((time_t *)NULL);
    printf("seconds = %d\n",seconds);
    
    return 0;
}

執(zhí)行結(jié)果為:

seconds = 1434620150

通常用戶得到日歷時間的秒數(shù)沒有實(shí)際的意義,但可以為時間轉(zhuǎn)化做一些輔助性質(zhì)的工作恳守。為了更好的利用時間考婴,用戶需要將這些秒數(shù)轉(zhuǎn)換為更易接受的時間表示方式,這些表示時間的方式有格林威治時間催烘、本地時間等沥阱。

3.2 stime()函數(shù)

【函數(shù)原型】:

#define _SVID_SOURCE /* glibc2 needs this */
#include <time.h>
int stime(time_t *t);

【函數(shù)說明】:

該函數(shù)用于設(shè)置系統(tǒng)時間,參數(shù)t指向time_t時間格式變量伊群,表示從UTC(coordinated universal time)時間1970年1月1日00時00分00秒(也稱為Linux系統(tǒng)的Epoch時間)到當(dāng)前時刻的秒數(shù)考杉。

函數(shù)執(zhí)行成功返回0,失敗返回-1舰始,并將錯誤代碼放在errno中崇棠。

3.3 gmtime()函數(shù)

【函數(shù)原型】:

#include <time.h>
struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);

【函數(shù)說明】:

該函數(shù)將time()函數(shù)獲取的日歷時間轉(zhuǎn)化為tm結(jié)構(gòu)體表示的格林威治標(biāo)準(zhǔn)時間,并保存在struct tm結(jié)構(gòu)體中丸卷。參數(shù)是time()函數(shù)獲取的日歷時間枕稀。

gmtime_r()是gmtime()的線程安全版本,在libc5.2.5及以后版本中可用谜嫉。

3.4 localtime()函數(shù)

【函數(shù)原型】:

#include <time.h>
struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);

【函數(shù)說明】:

該函數(shù)將time()函數(shù)獲取的日歷時間轉(zhuǎn)化為tm結(jié)構(gòu)體表示的本地時區(qū)時間萎坷,并保存至struct tm結(jié)構(gòu)體中。參數(shù)是time()函數(shù)獲取的日歷時間骄恶。

localtime_r()是localtime()的線程安全版本食铐,在libc5.2.5及以后版本中可用匕垫。

【使用實(shí)例】:

#include <stdio.h>
#include <time.h>
    
int main(void)
{
    time_t seconds = 0;
    struct tm *utc_time = NULL;
    struct tm *local_time = NULL;
    
    seconds = time((time_t *)NULL);
    printf("seconds = %d\n",seconds);
    utc_time = gmtime(&seconds);
    printf("UTC hour is   : %d\n",utc_time->tm_hour);
    local_time = localtime(&seconds);
    printf("Local hour is : %d\n",local_time->tm_hour);
    
    return 0;
}

執(zhí)行結(jié)果為:

seconds = 1434621313
UTC hour is : 9  //格林威治時間是9點(diǎn)
Local hour is : 17 //Linux系統(tǒng)的當(dāng)前時間是17點(diǎn)

在命令行中執(zhí)行data命令僧鲁,可以看到:

Thu Jun 18 17:59:30 CST 2015

說明date命令打印的是Linux系統(tǒng)的本地時間。

3.5 ctime()函數(shù)

【函數(shù)原型】:

#include <time.h>
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);

【函數(shù)說明】:

該函數(shù)將timep指向的日歷時間(time_t時間類型)轉(zhuǎn)化為本地時間的字符串形式象泵,并返回該字符串指針寞秃,參數(shù)是time()函數(shù)返回的日歷時間。

ctime_r()是ctime()的線程安全版本偶惠,在libc5.2.5及以后版本中可用春寿。

【函數(shù)使用步驟】:

使用time()獲取日歷時間—>使用ctime()將日歷時間直接轉(zhuǎn)換為本地時間字符串。

3.6 asctime()函數(shù)

【函數(shù)原型】:

#include <time.h>
time_t asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);

【函數(shù)說明】:

該函數(shù)將struct tm結(jié)構(gòu)體時間轉(zhuǎn)化為字符串形式忽孽,并返回該字符串指針绑改,參數(shù)是gmtime()函數(shù)或localtime()函數(shù)返回的struct tm結(jié)構(gòu)體時間。

asctime_r()是asctime()的線程安全版本兄一,在libc5.2.5及以后版本中可用厘线。

【函數(shù)使用步驟】:

  • 方法一:使用time()獲取日歷時間—>使用gmtime()將日歷時間轉(zhuǎn)化為格林威治時間—>使用asctime()將struct tm格式的時間轉(zhuǎn)化為字符串;
  • 方法二:使用time()獲取日歷時間—>使用localtime()將日歷時間轉(zhuǎn)化為本地時間—>使用asctime()將struct tm格式的時間轉(zhuǎn)化為字符串出革;

【使用例程】:

#include <stdio.h>
#include <time.h>
    
int main(void)
{
    time_t t;
    char *ptr;
    struct tm *utc;
    struct tm *local;
    
    t = time((time_t *)NULL);
    printf("seconds = %d\n",t);
    ptr = ctime(&t);
    printf("Local time is : %s\n",ptr);
    utc = gmtime(&t);
    ptr = asctime(utc);
    printf("UTC time is :%s\n",ptr);
    local = localtime(&t);
    ptr = asctime(local);
    printf("Local time is :%s\n",ptr);  
    
    return 0;
}

執(zhí)行結(jié)果為:

seconds = 1434622915
Local time is : Thu Jun 18 18:21:55 2015
UTC time is :Thu Jun 18 10:21:55 2015
Local time is :Thu Jun 18 18:21:55 2015

在命令行終端中執(zhí)行date命令造壮,結(jié)果如下:

Thu Jun 18 18:24:32 CST 2015

3.7 mktime()函數(shù)

【函數(shù)原型】:

#include <time.h>
time_t mktime(struct tm *p_tm);

【函數(shù)說明】:

該函數(shù)將p_tm指向的tm結(jié)構(gòu)體時間類型轉(zhuǎn)換成從1970年1月1日00時00分00秒至今的GMT時間經(jīng)過的秒數(shù)。

【函數(shù)實(shí)例】:

#include <time.h>
#include <stdio.h>
int main(void)
{
    time_t timep;
    struct tm *p_tm;
    
    timep = time((time_t *)NULL);
    printf("time():%d\n",timep);
    p_tm = local(&timep);
    timep = mktime(p_tm);
    printf("time()->localtime()->mktime():%d\n",timep);
    
    return 0;
}

3.8 difftime()函數(shù)

【函數(shù)原型】:

#include <time.h>
double difftime(time_t timep1, time_t timep2);

【函數(shù)說明】:

difftime()函數(shù)比較參數(shù)timep1和timep2時間是否相同骂束,并返回之間相差的秒數(shù)耳璧,返回類型為double成箫。

【使用實(shí)例】:

#include <time.h>
#include <stdio.h>
int main(void)
{
    time_t timep1,timep2;
    timep1 = time(NULL);
    sleep(2);
    timep2 = time(NULL);
    printf("The difference is %f seconds\n", difftime(timep1, timep2));
    return 0;
}

3.9 gettimeofday()函數(shù)

【函數(shù)原型】:

#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);

【函數(shù)說明】:

該函數(shù)用于獲取從UTC(coordinated universal time)時間1970年1月1日00時00分00秒(也稱為Linux系統(tǒng)的Epoch時間)到當(dāng)前時刻的時間差,并將此時間存入tv指向的結(jié)構(gòu)體中旨枯,當(dāng)?shù)貢r區(qū)信息則放到tz指向的結(jié)構(gòu)體中蹬昌;該函數(shù)常用于計(jì)算耗時。函數(shù)執(zhí)行成功返回0攀隔,否則返回-1凳厢,錯誤代碼存于errno。

【參數(shù)說明】:

參數(shù)tv用于存放返回從UTC(coordinated universal time)時間1970年1月1日00時00分00秒(也稱為Linux系統(tǒng)的Epoch時間)到當(dāng)前時刻的時差竞慢,時間差以秒或微妙為單位先紫;

參數(shù)tz常設(shè)置為NULL,因?yàn)閘ibc或glibc中并未支持tz筹煮,因此在Linux中未使用遮精;struct timezone結(jié)構(gòu)體定義如下:

#include <sys/time.h>
struct timezone {
    int   tz_minuteswest;  /* miniutes west of Greenwich:和GMT時間差了多少分鐘 */
    int   tz_dsttime;      /* type of DST correction:日光節(jié)約時間的狀態(tài) */
};

tz_dsttime所代表的狀態(tài)如下:

DST_NONE    /* not on dst */
DST_USA     /* USA style dst */
DST_AUST    /* Australian style dst */
DST_WET     /* Western European dst */
DST_MET     /* Middle European dst */
DST_EET     /* Eastern European dst */
DST_CAN     /* Canada */
DST_GB      /* Great Britain and Eire */
DST_RUM     /* Rumania */
DST_TUR     /* Turkey */
DST_AUSTALT /* Australian style with shift in 1986 */

【常用用法】:

在做某件事之前調(diào)用gettimeofday(),在做完該事情之后調(diào)用gettimeofday()败潦,兩個函數(shù)的tv參數(shù)返回值的差就是該事件所消耗的時間本冲。

【使用實(shí)例】:

#include <stdio.h>
#include <sys/time.h>
    
void function(void)
{
    unsigned int i,j,k;
    
    for(i = 0;i < 500;i++)
        for(j = 0;j < 500;j++)
            k++;
}
int main(void)
{
    time_t t;
    float timeuse;
    struct timeval tpstart,tpend;
    t = time((time_t *)NULL);
    printf("seconds is %d\n",t);
    gettimeofday(&tpstart,NULL);
    printf("seconds is %d,usec is %d\n",tpstart.tv_sec,tpstart.tv_usec);
    function();
    gettimeofday(&tpend,NULL);
    timeuse = 1000*1000*(tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
    timeuse /= 1000*1000;
    printf("User time:%f\n",timeuse);
    
    return 0;
}
執(zhí)行結(jié)果為:
User time:0.000727

3.10 settimeofday()函數(shù)

【函數(shù)原型】:

#include <sys/time.h>
int settimeofday(const struct timeval *tv , const struct timezone *tz);

【函數(shù)說明】:

該函數(shù)把當(dāng)前時間設(shè)成由tv指向的結(jié)構(gòu)體數(shù)據(jù);當(dāng)tz指針不為空時劫扒,則設(shè)成tz指向的結(jié)構(gòu)體數(shù)據(jù)檬洞。函數(shù)執(zhí)行成功返回0,否則返回-1沟饥,錯誤代碼存于errno添怔。只有root權(quán)限才能使用此函數(shù)修改時間。

3.11 strftime()函數(shù)

【函數(shù)原型】:

#include <time.h>
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);

【函數(shù)說明】:

該函數(shù)將參數(shù)tm結(jié)構(gòu)的時間結(jié)構(gòu)贤旷,參照參數(shù)format所指定的字符串格式做轉(zhuǎn)換广料,轉(zhuǎn)換后的字符串內(nèi)容將復(fù)制到參數(shù)s所指的字符串?dāng)?shù)組中,該字符串的最大長度為參數(shù)max所控制幼驶。下面是參數(shù)format的格式指令:

  • %a:當(dāng)?shù)匦瞧谌掌诘拿Q縮寫艾杏,如Sun;
  • %A:當(dāng)?shù)匦瞧谌掌诘拿Q全稱,如Sunday;
  • %b:當(dāng)?shù)卦路莸挠⑽目s寫敌土;
  • %h:當(dāng)?shù)卦路莸挠⑽目s寫券敌;
  • %B:當(dāng)?shù)卦路莸拿Q全稱;
  • %m:月份,表示法為01~12;
  • %C:以year/100表示年份;
  • %d:月里的天數(shù)元旬,表示法為01~31;
  • %e:月里的天數(shù),表示法為1~31匀归;
  • %c:當(dāng)?shù)剡m當(dāng)?shù)娜掌谂c時間表示法表示完整時間坑资;
  • %H:以24小時制表示小時數(shù),表示法為00~23穆端;
  • %k:以24小時制表示小時數(shù)袱贮,表示法為0~23;
  • %l:以12小時制表示小時數(shù)体啰,表示法為01~12攒巍;
  • %M:分鐘數(shù),表示法為00~59荒勇;
  • %S:秒數(shù)柒莉,00~59;
  • %s:從1970年1月1日0時算起至今的UTC時間所經(jīng)過的秒數(shù)沽翔;
  • %j:一年中的天數(shù)(001~366)兢孝;
  • %u:一星期中的星期日期,范圍1~7仅偎,星期一從1開始跨蟹;
  • %U:一年中的星期數(shù)(00~53),一月第一個星期日開始為01橘沥;
  • %w:一星期中的星期日期窗轩,范圍0~6,星期日從0開始座咆;
  • %W:一年中的星期數(shù)(00~53)痢艺,一月第一個星期一開始為01;
  • %p:顯示對應(yīng)的AM或PM箫措;
  • %P:顯示對應(yīng)的am或pm腹备;
  • %R:相當(dāng)于使用“%H:%M”格式衬潦;
  • %r:相當(dāng)于使用“%I:%M:%S %P”格式斤蔓;
  • %D:相當(dāng)于“%m%d%y”格式,如06/19/15镀岛;
  • %T:24小時時間表示弦牡,相當(dāng)于“%H:%M:%S”格式;
  • %x:當(dāng)?shù)剡m當(dāng)?shù)娜掌诒硎灸暝氯眨?/li>
  • %X:當(dāng)?shù)剡m當(dāng)?shù)臅r間表示時分秒漂羊;
  • %y:一世紀(jì)中的年份表示驾锰;
  • %Y:完整的公元年份表示;
  • %Z:使用的時區(qū)名稱走越;
  • %n:同\n椭豫;
  • %t:同\t;
  • %%:%符號;

返回值復(fù)制到參數(shù)s所指的字符串?dāng)?shù)組的總字符數(shù)赏酥,不包括字符串結(jié)束符喳整。如果返回0,表示未復(fù)制字符串到參數(shù)s內(nèi)裸扶,但不表示一定有錯誤發(fā)生框都。環(huán)境變量TZ和TC_TIME會影響此函數(shù)結(jié)果。

【使用實(shí)例】:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
    
int main(int argc, char *argv[])
{
    char outstr[200];
    time_t t;
    struct tm *tmp;
    
    t = time(NULL);
    tmp = localtime(&t);
    if (tmp == NULL) {
        perror("localtime");
        exit(EXIT_FAILURE);
    }
    if (strftime(outstr, sizeof(outstr), argv[1], tmp) == 0) {
        fprintf(stderr, "strftime returned 0");
        exit(EXIT_FAILURE);
    }
    
    printf("Result string is \"%s\"\n", outstr);
    exit(EXIT_SUCCESS);
} /* main */

3.12 strptime()函數(shù)

【函數(shù)原型】:

#define _XOPEN_SOURCE /* glibc2 needs this */
#include <time.h>
char *strptime(const char *s, const char *format, struct tm *tm);

【函數(shù)說明】:

該函數(shù)與scanf類似呵晨,同strftime()函數(shù)相反魏保,將一個字符串格式時間解釋稱為struct tm格式時間。

【使用實(shí)例】:

#include <stdio.h>
#include <time.h>
    
int main() {
    struct tm tm;
    char buf[255];
    
    strptime("2001-11-12 18:31:01", "%Y-%m-%d %H:%M:%S", &tm);
    strftime(buf, sizeof(buf), "%d %b %Y %H:%M", &tm);
    puts(buf);
    return 0;
}

3.13 clock()函數(shù)

【函數(shù)原型】:

#include <time.h>
clock_t clock(void);

【函數(shù)說明】:

該函數(shù)用來返回進(jìn)程所占用CPU的大約時間摸屠。

3.14 ftime()函數(shù)

【函數(shù)原型】:

#include <sys/timeb.h>
int ftime(struct timeb *tp);

【函數(shù)說明】:

該函數(shù)將日前時間日期由參數(shù)tp所指向的結(jié)構(gòu)體輸出谓罗,該函數(shù)無論成功還是失敗都返回0。struct timep結(jié)構(gòu)體定義如下:

struct timeb{
    time_t time;  /* 從1970年1月1日0點(diǎn)至今的秒數(shù) */
    unsigned short millitm;  /* 為千分之一秒 */
    short timezone; /* 為目前時區(qū)和Greenwich相差的時間季二,單位為妙 */
    short dstflag;  /* 為日光節(jié)約時間的修正狀態(tài)妥衣,若非0為啟用日光節(jié)約時間的修正 */
};

ftime()函數(shù)在4.2的BSD中支持。

3.15 tzset()函數(shù)

【函數(shù)原型】:

#include <time.h>
void tzset(void);
extern char *tzname[2];
extern long timezone;
extern int daylight;

【函數(shù)說明】:

該函數(shù)將環(huán)境變量TZ設(shè)給全局變量tzname戒傻,也就是從環(huán)境變量取得目前當(dāng)?shù)氐臅r區(qū)税手,時間轉(zhuǎn)換函數(shù)會自動調(diào)用此函數(shù)。若TZ為設(shè)置需纳,tzname會依照/etc/localtime找出最接近當(dāng)?shù)氐臅r區(qū)芦倒。若TZ為NULL,或是無法判認(rèn)不翩,則使用UTC時區(qū)兵扬。此函數(shù)總是成功,并初始化tzname口蝠。

四器钟、Linux休眠編程接口

有時候?yàn)榱私档虲PU的占用率及程序的運(yùn)行速度,需要讓程序休眠一段時間妙蔗,在Linux應(yīng)用程序中傲霸,可以使用:sleep()和usleep()函數(shù)實(shí)現(xiàn)。對應(yīng)Linux內(nèi)核中眉反,休眠的函數(shù)有:udelay()昙啄、ndelay()、mdelay()寸五。delay函數(shù)是忙等待梳凛,占用CPU時間,而sleep函數(shù)使調(diào)用進(jìn)程休眠梳杏,并不占用CPU時間韧拒。

4.1 sleep()函數(shù)

【函數(shù)原型】:

#include <unistd.h>
unsigned int sleep(unsigned int seconds);

【函數(shù)說明】:

該函數(shù)使調(diào)用sleep()的程序休眠淹接,直到seconds秒之后才被喚醒。該函數(shù)返回0(seconds時間到了)叛溢,或返回seconds還剩余的秒數(shù)蹈集。

4.2 usleep()函數(shù)

【函數(shù)原型】:

/* BSD version */
#include <unistd.h>
void usleep(unsigned long usec);
    
/* SUSv2 version */
#define _XOPEN_SOURCE 500
#include <unistd.h>
int usleep(useconds_t usec);

【函數(shù)說明】:

該函數(shù)使調(diào)用usleep()的程序休眠,直到usec微妙之后才被喚醒雇初。該函數(shù)睡眠的實(shí)際時間會比usec略有延長拢肆,因?yàn)槿魏蜗到y(tǒng)活動和時間處理調(diào)用的微處理粒度。

該函數(shù)執(zhí)行成功返回0靖诗,失敗返回-1郭怪。該函數(shù)可以被信號喚醒,同時返回EINTR刊橘。

五鄙才、Linux定時鬧鐘編程接口

Linux應(yīng)用程序?yàn)槲覀兊拿恳粋€進(jìn)程提供了一個定時鬧鐘alarm,當(dāng)定時器指定的時間到時促绵,系統(tǒng)會向調(diào)用進(jìn)程發(fā)送SIGALARM信號攒庵,如果忽略或者不捕獲此信號,則其默認(rèn)動作是終止調(diào)用該alarm函數(shù)的進(jìn)程败晴;當(dāng)然也可以通過signal()函數(shù)向系統(tǒng)注冊一個自己的定時鬧鐘處理函數(shù)浓冒。關(guān)于信號處理方面的知識,可參照信號相關(guān)章節(jié)的內(nèi)容尖坤。

5.1 alarm()函數(shù)

【函數(shù)原型】:

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

【函數(shù)說明】:

alarm()函數(shù)向系統(tǒng)設(shè)定一個鬧鐘稳懒,并在鬧鐘時間到時內(nèi)核向該進(jìn)程發(fā)送SIGALRM信號。

【注意事項(xiàng)】:

  • 一個進(jìn)程只能有一個alarm鬧鐘慢味;
  • 鬧鐘時間到了后场梆,若不再次調(diào)用alarm(),將不會有新的鬧鐘產(chǎn)生纯路;
  • 任何以seconds非0的調(diào)用或油,都將重新更新鬧鐘定時時間,并返回上一個鬧鐘剩余時間驰唬;若為第一次設(shè)置鬧鐘顶岸,則返回0;以seconds為0的調(diào)用定嗓,表示取消以前的鬧鐘蜕琴,并將剩余時間返回。
  • 在Linux系統(tǒng)中提到宵溅,sleep()有可能是使用alarm()來實(shí)現(xiàn)的,因此上炎,在一個進(jìn)程中同時使用alarm()和sleep()并不明智恃逻。

【使用實(shí)例】:

#include <stdio.h>
#include <unistd.h>
    
int main(void)
{
    int ret;
    sleep(3);
    ret = alarm(3);
    printf("%d\n",ret);
    pause();
    printf("This will not been print.\n");
    return 0;
}

執(zhí)行結(jié)果為:

0   //第一次為該進(jìn)程設(shè)置鬧鐘
Alarm clock

注意最后一個printf并未打印出來雏搂,因?yàn)槌绦驔]有注冊SIGALARM信號處理函數(shù),系統(tǒng)默認(rèn)處理動作是結(jié)束alarm()調(diào)用進(jìn)程寇损。

5.2 setitimer()函數(shù)

Linux系統(tǒng)為每個進(jìn)程提供了三個獨(dú)立的計(jì)時器凸郑,每個計(jì)時器在不同的時域中遞減。當(dāng)任何一個定時器到點(diǎn)了矛市,都會向進(jìn)程發(fā)送一個信號芙沥,并且重啟計(jì)時器。

【函數(shù)原型】:

#include <sys/time.h>
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);

【函數(shù)說明】:

getitimer()函數(shù)獲取ITIMER_REAL浊吏、ITIMER_VIRTUAL或ITIMER_PROF三個定時器中的一個的時間信息而昨,并保存到value指向的對象中。

setitimer()函數(shù)設(shè)置ITIMER_REAL找田、ITIMER_VIRTUAL或ITIMER_PROF三個定時器中的一個的定時時間為value指向的對象歌憨,若ovalue非空,則將老的時間信息保存到該對象中墩衙。

setitimer()比alarm()功能更加強(qiáng)大务嫡,支持3種類型的定時器(但setitimer()并不是標(biāo)準(zhǔn)C庫的函數(shù)):

  • ITIMER_REAL:以系統(tǒng)真實(shí)的時間來計(jì)算,它會送出SIGALRM信號漆改;
  • ITIMER_PROF:以該進(jìn)程在用戶態(tài)下和內(nèi)核態(tài)下所費(fèi)時間來計(jì)算心铃,它送出SIGPROF信號;
  • ITIMER_VIRTUAL:以該進(jìn)程在用戶態(tài)下花費(fèi)的時間來計(jì)算挫剑,它送出SIGVTALRM信號于个;

該函數(shù)執(zhí)行成功返回0,失敗返回-1暮顺,并將錯誤號存放在errno中厅篓。

【參數(shù)說明】:

witch用于指定定時器類型,其取值為上面三種之一捶码;value是struct itimerval的一個實(shí)例羽氮;ovalue參數(shù)不做處理。struct itimerval結(jié)構(gòu)體定義如下:

struct itimerval {
    struct timeval it_interval; /* next value */
    struct timeval it_value;    /* current value */
};
struct timeval {
    long tv_sec;                /* seconds */
    long tv_usec;               /* microseconds */
};

it_value變量用于設(shè)置計(jì)時器的計(jì)時時間惫恼,為0時表示禁止档押;it_interval變量用于設(shè)置當(dāng)計(jì)時器到時,重置的時間祈纯,從而實(shí)現(xiàn)循環(huán)定時令宿。也就是說,計(jì)時器從it_value開始遞減腕窥,當(dāng)遞減到0時粒没,向進(jìn)程發(fā)送一個信號,并重置定時器為it_interval簇爆,如此循環(huán)癞松,從而可以實(shí)現(xiàn)循環(huán)鬧鐘的功能爽撒。

【使用實(shí)例】:

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
void sig_func(int signo)
{
    printf("Catch a signal.\n");
    static int realCnt = 0;
    static int virtualCnt = 0;
    switch(signo)
    {
        case SIGALRM:
            printf("The %d times:SIGALRM\n",realCnt++);
            break;
        case SIGVTALRM:
            printf("The %d times:SIGVTALRM\n",virtualCnt++);
            break;
        default:
            break;
    }
}
int main(void)
{
    struct itimerval tv,tv1,otv;
    signal(SIGALRM,sig_func);
    signal(SIGVTALRM,sig_func);
    //how long to run the first time
    tv.it_value.tv_sec = 3;
    tv.it_value.tv_usec = 0;
    //after the first time,how long to run next time
    tv.it_interval.tv_sec = 2;
    tv.it_interval.tv_usec = 0;
    if(setitimer(ITIMER_REAL,&tv,&otv) != 0)
    {
        printf("setitimer err %d\n",errno);
        return -1;
    }
    tv1.it_value.tv_sec = 1;
    tv1.it_value.tv_usec = 0;
    tv1.it_interval.tv_sec = 1;
    tv1.it_interval.tv_usec = 0;
    if(setitimer(ITIMER_VIRTUAL,&tv1,&otv) != 0)
    {
        printf("setitimer err %d\n",errno);
        return -1;
    }
    while(1)
    {
        sleep(30);
        printf("otv:%d,%d,%d,%d\n",otv.it_value.tv_sec,otv.it_value.tv_usec,
                                        otv.it_interval.tv_sec,otv.it_interval.tv_usec);
    }
    return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市响蓉,隨后出現(xiàn)的幾起案子硕勿,更是在濱河造成了極大的恐慌,老刑警劉巖枫甲,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件源武,死亡現(xiàn)場離奇詭異,居然都是意外死亡想幻,警方通過查閱死者的電腦和手機(jī)粱栖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來举畸,“玉大人查排,你說我怎么就攤上這事〕冢” “怎么了跋核?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叛买。 經(jīng)常有香客問我砂代,道長,這世上最難降的妖魔是什么率挣? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任刻伊,我火速辦了婚禮,結(jié)果婚禮上椒功,老公的妹妹穿的比我還像新娘捶箱。我一直安慰自己,他們只是感情好动漾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布丁屎。 她就那樣靜靜地躺著,像睡著了一般旱眯。 火紅的嫁衣襯著肌膚如雪晨川。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天删豺,我揣著相機(jī)與錄音共虑,去河邊找鬼。 笑死呀页,一個胖子當(dāng)著我的面吹牛妈拌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赔桌,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼供炎,長吁一口氣:“原來是場噩夢啊……” “哼渴逻!你這毒婦竟也來了疾党?” 一聲冷哼從身側(cè)響起音诫,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雪位,沒想到半個月后竭钝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雹洗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年香罐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片时肿。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡庇茫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出螃成,到底是詐尸還是另有隱情旦签,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布寸宏,位于F島的核電站宁炫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏氮凝。R本人自食惡果不足惜羔巢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望罩阵。 院中可真熱鬧竿秆,春花似錦、人聲如沸稿壁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽常摧。三九已至搅吁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間落午,已是汗流浹背谎懦。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留溃斋,地道東北人界拦。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像梗劫,于是被迫代替她去往敵國和親享甸。 傳聞我的和親對象是個殘疾皇子截碴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 常用模塊 認(rèn)識模塊 什么是模塊 什么是模塊日丹? 常見的場景:一個模塊就是一個包含了python定義和聲明的文件,文...
    go以恒閱讀 1,943評論 0 6
  • 一.概念 在C/C++中蚯嫌,通過學(xué)習(xí)許多C/C++庫哲虾,你可以有很多操作、使用時間的方法择示。但在這之前你需要了解一些“時...
    小辰帶你看世界閱讀 1,324評論 0 1
  • 進(jìn)程 創(chuàng)建 創(chuàng)建進(jìn)程用fork()函數(shù)束凑。fork()為子進(jìn)程創(chuàng)建新的地址空間并且拷貝頁表。子進(jìn)程的虛擬地址空間...
    梅花怒閱讀 1,891評論 0 7
  • 要保姆就不要奢望保姆愛你栅盲,除非是你媽 要感情就不要抱怨錢太少 要錢就別感情用事 當(dāng)然不排除又有錢又會照顧人又愛你的...
    sabrina_852c閱讀 173評論 0 0
  • 不要以為待業(yè)在家就可以每天睡到自然醒汪诉。工作日我每天都要6:30起床,D先生偶爾還可以睡一下懶覺谈秫,我卻不可以扒寄。 這是...
    九月露水閱讀 322評論 0 0