LinuxUNIX系统编程手册——(十)时间

程序可能会关注两种时间类型。

  • 真实时间:度量这一时间的起点有二:一为某个标准点;二为进程生命周期内的某个固定时点(通常为程序启动)。前者为日历(calendar)时间,适用于需要对数据库记录或文件打上时间戳的程序;后者则称之为流逝(elapsed)时间或挂钟(wallclock)时间,主要针对需要周期性操作或定期从外部输入设备进行度量的程序。
  • 进程时间:一个进程所使用的 CPU 时间总量,适用于对程序、算法性能的检查或优化。

10.1 日历时间(Calendar Time)

time()系统调用返回自 Epoch 以来的秒数。

#include <time.h>

time_t time(time_t *timep);			/* 返回自 Epoch 以来的秒数,错误返回(time_t)-1 */

如果 timep 参数不为 NULL,那么还会将自 Epoch 以来的秒数置于 timep 所指向的位置。由于 time()会以两种方式返回相同的值,而使用时唯一可能出错的地方是赋予 timep 参数一个无效地址(EFAULT),因此往往会简单地采用如下调用(不做错误检查):

t= time(NULL);

10.2 时间转换函数

下图 所示为用于在 time_t 值和其他时间格式之间相互转换的函数,其中包括打印输出。这些函数屏蔽了因时区、夏令时(DST)制和本地化等问题给转换所带来的种种复杂性。

在这里插入图片描述

10.2.1 将 time_t 转换为可打印格式

为了将 time_t 转换为可打印格式,ctime()函数提供了一个简单方法。

#include <time.h>

char *ctime(const time_t *timep);		/* 成功返回一个长达 26 字节的字符串,内含标准格式的日期和时间
如"Wed Jul 24 10:38:55 2024",包含换行符和终止空字节各一,失败返回NULL */

ctime()函数在进行转换时,会自动对本地时区和 DST 设置加以考虑(10.3 节将解释这些设置的确定过程)。返回的字符串经由静态分配,下一次对 ctime()的调用会将其覆盖。

10.2.2 time_t 和分解时间之间的转换

函数 gmtime()和 localtime()可将一 time_t 值转换为一个所谓的分解时间(broken-down time)。分解时间被置于一个经由静态分配的结构中,其地址则作为函数结果返回。

#include <time.h>

struct tm *gmtime(const time_t *timep);			/* 返回一个指向tm类型的结构体,错误返回NULL */		
struct tm *localtime(const time_t *timep);		/* 返回一个指向tm类型的结构体,错误返回NULL */
struct tm
{
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;		/* Daylight saving time flag
    						> 0: DST is in effect
    						= 0: DST is not effect
    						< 0: DST information not acailable */
}

函数 gmtime()能够把日历时间转换为一个对应于 UTC 的分解时间。(字母 GM 源于格林威治标准时间)。相形之下,函数 localtime()需要考虑时区和夏令时设置,返回对应于系统本地时间的一个分解时间。

函数 mktime() 将一个本地时区的分解时间翻译为 time_t 值,并将其作为函数结果返回。调用者将分解时间置于一个 tm 结构,再以 timeptr 指针指向该结构。这一转换会忽略输入 tm结构中的 tm_wday 和 tm_yday 字段。

#include <time.h>

time_t mktime(struct tm *timeptr);			/* 成功返回自 Epoch 以来的秒数,失败返回(time_t)-1 */

函数 mktime()可能会修改 timeptr 所指向的结构体,至少会确保对 tm_wday 和 tm_yday 字段值的设置,会与其他输入字段的值能对应起来。

此外,mktime()不要求 tm 结构体的其他字段受到前述范围的限制。任何一个字段的值超出范围,mktime()都会将其调整回有效范围之内,并适当调整其他字段。所有这些调整,均发生于 mktime()更新 tm_wday 和 tm_yday 字段并计算返回值 time_t 之前。

mktime()在进行转换时会对时区进行设置。此外,DST 设置的使用与否取决于输入字段tm_isdst 的值。

  • 若 tm_isdst 为 0,则将这一时间视为标准间(即,忽略夏令时,即使实际上每年的这一时刻处于夏令时阶段)。
  • 若 tm_isdst 大于 0,则将这一时间视为夏令时(即,夏令时生效,即使每年的此时不处于夏令时阶段)。
  • 若 tm_isdst 小于 0,则试图判定 DTS 在每年的这一时间是否生效。这往往是众望所归的设置。

10.2.3 分解时间和打印格式之间的转换

从分解时间转换为打印格式

在参数 tm 中提供一个指向分解时间结构的指针,asctime()则会返回一指针,指向经由静态分配的字符串,内含时间,格式则与 ctime ()相同。该时间通常要么已然通过 localtime()作了本地化处理,要么早已经由 gmtime()转换成了 UTC。

#include <time.h>

char *asctime(const struct tm *timeptr);		/* 成功返回一个指向保存时间的由静态分配的字符串的指针,出错返回NULL */

程序示例:获取和转换日历时间

#include <locale.h>
#include <time.h>
#include <sys/time.h>
#include "tlpi_hdr.h"

#define SECONDS_IN_TROPICAL_YEAR (365.24219 * 24 * 60 * 60)

int
main(int argc, char *argv[])
{
    time_t t;
    struct tm *gmp, *locp;
    struct tm gm, loc;
    struct timeval tv;

    t = time(NULL);				/* 获取自 Epoch 以来的秒数*/
    printf("Seconds since the Epoch (1 Jan 1970): %ld", (long) t);
    printf(" (about %6.3f years)\n", t / SECONDS_IN_TROPICAL_YEAR);

    if (gettimeofday(&tv, NULL) == -1)			/* 获取自 Epoch 以来的秒数*/
        errExit("gettimeofday");
    printf("  gettimeofday() returned %ld secs, %ld microsecs\n",
            (long) tv.tv_sec, (long) tv.tv_usec);

    gmp = gmtime(&t);			/* 将自 Epoch 以来的秒数转换为对应于UTC的分解时间 */
    if (gmp == NULL)
        errExit("gmtime");

    gm = *gmp;          /* 由于asctime() 或者 gmtime()可能会修改*gmp,先保存一下 */
    printf("Broken down by gmtime():\n");
    printf("  year=%d mon=%d mday=%d hour=%d min=%d sec=%d ", gm.tm_year,
            gm.tm_mon, gm.tm_mday, gm.tm_hour, gm.tm_min, gm.tm_sec);
    printf("wday=%d yday=%d isdst=%d\n", gm.tm_wday, gm.tm_yday, gm.tm_isdst);

    locp = localtime(&t);			/* 将自 Epoch 以来的秒数转换为对应于于系统本地时间的分解时间 */
    if (locp == NULL)
        errExit("localtime");

    loc = *locp;        /* 保存一下 */

    /* 使用分解时间进行输出 */
    printf("Broken down by localtime():\n");
    printf("  year=%d mon=%d mday=%d hour=%d min=%d sec=%d ",
            loc.tm_year, loc.tm_mon, loc.tm_mday,
            loc.tm_hour, loc.tm_min, loc.tm_sec);
    printf("wday=%d yday=%d isdst=%d\n\n",
            loc.tm_wday, loc.tm_yday, loc.tm_isdst);

    printf("asctime() formats the gmtime() value as: %s", asctime(&gm));	/* 将分解时间转换为标准格式的时间并输出 */
    printf("ctime() formats the time() value as:     %s", ctime(&t));		/* 将time_t格式的时间转换为标准格式的时间并输出 */

    printf("mktime() of gmtime() value:    %ld secs\n", (long) mktime(&gm));	/* 将分解时间转换为time_t格式的时间并输出 */
    printf("mktime() of localtime() value: %ld secs\n", (long) mktime(&loc));	/* 将分解时间转换为time_t格式的时间并输出 */

    exit(EXIT_SUCCESS);
}
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ g++ calendar_time.c -o calendar_time -ltlpi
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ ./calendar_time 
Seconds since the Epoch (1 Jan 1970): 1721760272 (about 54.560 years)
  gettimeofday() returned 1721760272 secs, 298461 microsecs
Broken down by gmtime():
  year=124 mon=6 mday=23 hour=18 min=44 sec=32 wday=2 yday=204 isdst=0
Broken down by localtime():
  year=124 mon=6 mday=24 hour=2 min=44 sec=32 wday=3 yday=205 isdst=0

asctime() formats the gmtime() value as: Tue Jul 23 18:44:32 2024
ctime() formats the time() value as:     Wed Jul 24 02:44:32 2024
mktime() of gmtime() value:    1721731472 secs
mktime() of localtime() value: 1721760272 secs

当把一个分解时间转换成打印格式时,函数 strftime()可以提供更为精确的控制。令 timeptr指向分解时间,strftime()会将以 null 结尾、由日期和时间组成的相应字符串置于 outstr 所指向的缓冲区中。

#include <time.h>
/* 成功返回 outstr 所指缓冲区的字节长度,且不包括终止空字节,如果结果字符串的总长度,含终止空字节,
超过了 maxsize 参数则返回0,且此时无法确定 outstr 的内容 */
size_t strftime(char *outstr, size_t maxsize, const char *format, const struct tm *timeptr);

outstr 中返回的字符串按照 format 参数定义的格式做了格式化。maxsize 参数指定 outstr 的最大长度。不同于 ctime()和 asctime(),strftime()不会在字符串的结尾包括换行符(除非 format 中定义有换行符)。

strftime()的 format 参数是一字符串,与赋予 printf()的参数相类似。冠以百分号(%)的字符序列是对转换的定义,函数会将百分号后的说明符字符一一替换为日期和时间的组成部分,详细遇到之后查表即可。

函数currTime(),其返回一字符串,内含 strftime()按 format 参数格式化的当前时间。

#include "curr_time.h"

char *currTime(const char *format);		/* 成功返回一个指向静态分配字符串的指针,失败返回NULL */

将打印格式时间转换为分解时间

函数 strptime()是 strftime()的逆向函数,将包含日期和时间的字符串转换成一分解时间。函数strptime()按照参数format内的格式要求,对由日期和时间组成的字符串str加以解析,并将转换后的分解时间置于指针 timeptr 所指向的结构体中。

#include <time.h>

char *strptime(const char *str, const char *format, struct tm *timeptr);	
/* 成功返回一指向str中下一个未经处理的字符的指针,如果无法匹配整个格式字符串,返回NULL表示错误 */

strptime()的格式规范类似于 scanf(3),包含以下类型的字符。

  • 转换字符串冠以一个百分号(%)字符。
  • 如包含空格字符,则意味着其可匹配零个或多个空格。
  • (%之外的)非空格字符必须和输入字符串中的相同字符严格匹配。

程序清单 :获取和转换日历时间

/******************************************time/strtime.c******************************************/
#define _XOPEN_SOURCE
#include <time.h>
#include <locale.h>
#include "tlpi_hdr.h"

#define SBUF_SIZE 1000

int
main(int argc, char *argv[])
{
    struct tm tm;
    char sbuf[SBUF_SIZE];
    char *ofmt;

    if (argc < 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s input-date-time in-format [out-format]\n", argv[0]);

    if (setlocale(LC_ALL, "") == NULL)		/* 从环境变量取得地区的设置,并将指定设置地区的所有部分的值 */
        errExit("setlocale");   

    memset(&tm, 0, sizeof(struct tm));          /* 初始化tm */
    if (strptime(argv[1], argv[2], &tm) == NULL)		/* 根据argv[2]中的格式要求对argv[1]进行解析并存入tm */
        fatal("strptime");

    tm.tm_isdst = -1;           /* tm.tm_isdst不被strptime()设置,手动设置DST信息无法获得 */
    printf("calendar time (seconds since Epoch): %ld\n", (long) mktime(&tm));

    ofmt = (argc > 3) ? argv[3] : "%H:%M:%S %A, %d %B %Y %Z";		/* 有argv[3]以argv[3]为格式,无argv[3]则取默认格式 */
    if (strftime(sbuf, SBUF_SIZE, ofmt, &tm) == 0)		/* 把tm中的分解时间根据上面采取的格式转换为打印格式 */
        fatal("strftime returned 0");
    printf("strftime() yields: %s\n", sbuf);

    exit(EXIT_SUCCESS);
}
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ ./strtime "11:34:55am 24 Jul 2024" "%I:%M:%S%p %d %b %Y"
calendar time (seconds since Epoch): 1721792095
strftime() yields: 11:34:55 Wednesday, 24 July 2024 CST
# 以下用法与之相似,只不过这次为 strftime()明确指定了格式:
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ ./strtime "11:34:55am 24 Jul 2024" "%I:%M:%S%p %d %b %Y" "%F %T"
calendar time (seconds since Epoch): 1721792095
strftime() yields: 2024-07-24 11:34:55

10.3 时区

10.3.1 时区定义

系统没有将时区信息直接编码于程序或函数库中,而是以标准格式保存于文件中,并加以维护。这些文件位于目录/usr/share/zoneinfo 中。该目录下的每个文件都包含了一个特定国家或地区内时区制度的相关信息,且往往根据其所描述的时区来加以命名,诸如CST(中国标准时间)、EST(美国东部标准时间)、CET(欧洲中部时间)、UTC、Turkey 和 Iran。

系统的本地时间由时区文件/etc/localtime 定义,通常链接到/usr/share/zoneinfo 下的一个文件。

10.3.2 为程序指定时区

为运行中的程序指定一个时区,需要将 TZ 环境变量设置为由一冒号(:)和时区名称组成的字符串,其中时区名称定义于/usr/share/zoneinfo 中。设置时区会自动影响到函数 ctime()、localtime()、mktime()和 strftime()。

为了获取当前的时区设置,上述函数都会调用 tzset(3),函数 tzset()会首先检查环境变量 TZ。如果尚未设置该变量,那么就采用/etc/localtime 中定义的默认时区来初始化时区。如果 TZ 环境变量的值为空,或无法与时区文件名相匹配,那么就使用 UTC。还可将 TZDIR 环境变量(非标准的 GNU 扩展)设置为搜寻时区信息的目录名称,以替代默认的/usr/share/zoneinfo 目录。

#include <time.h>
#include <locale.h>
#include "tlpi_hdr.h"

#define BUF_SIZE 200

int
main(int argc, char *argv[])
{
    time_t t;
    struct tm *loc;
    char buf[BUF_SIZE];

    if (setlocale(LC_ALL, "") == NULL)		
        errExit("setlocale");   /* Use locale settings in conversions */

    t = time(NULL);

    printf("ctime() of time() value is:  %s", ctime(&t));

    loc = localtime(&t);
    if (loc == NULL)
        errExit("localtime");

    printf("asctime() of local time is:  %s", asctime(loc));

    if (strftime(buf, BUF_SIZE, "%A, %d %B %Y, %H:%M:%S %Z", loc) == 0)
        fatal("strftime returned 0");
    printf("strftime() of local time is: %s\n", buf);

    exit(EXIT_SUCCESS);
}
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ export TZ='Pacific/Auckland'
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ echo $TZ
Pacific/Auckland
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ ./show_time
ctime() of time() value is:  Wed Jul 24 14:05:09 2024
asctime() of local time is:  Wed Jul 24 14:05:09 2024
strftime() of local time is: Wednesday, 24 July 2024, 14:05:09 NZST
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ TZ=":Pacific/Auckland" ./show_time 
ctime() of time() value is:  Wed Jul 24 14:07:40 2024
asctime() of local time is:  Wed Jul 24 14:07:40 2024
strftime() of local time is: Wednesday, 24 July 2024, 14:07:40 NZST

10.4 地区(Locale)

10.4.1地区定义

地区信息维护于/usr/share/local(在一些发行版本中为/usr/lib/local)之下的目录层次结构中。该目录下的每个子目录都包含一特定地区的信息。这些目录的命名约定如下:language[_territory[.codest]][@modifier]

language 是双字母的 ISO 语言代码。territory 是双字母的 ISO 国家代码。codeset 表示字符编码集。modifier 则提供了一种方法,用以区分多个地区目录下 language、territory 和 codeset均相同的状况。de_DE.utf-8@euro 是完整地区目录名称的例子之一,代表地区如下:德语,德国,UTF - 8 字符编码,并采用欧元作为货币单位。

当在程序中指定要使用的地区时,实际上是指定了/usr /share/locale 下某个子目录的名称。如果程序指定地区不与任何子目录名称相匹配,那么 C 语言函数库将按如下顺序将各部分从指定地区(locale)中剥离,以寻求匹配:

  1. codeset
  2. normalized codeset
  3. territory
  4. modifier

每个地区子目录中包括有标准的一套文件,指定了此地区的约定设置,如下表。

文件名目的
LC_CTYPE该文件包含字符分类(参见 isalpha(3)手册页)以及大小写转换规则
LC_COLLATE该文件包含针对一字符集的排序规则
LC_MONETARY该文件包含对币值的格式化规则(见 localeconv(3)和<locale.h>)
LC_NUMERIC该文件包含对币值以外数字的格式化规则(见 localeconv(3)和<locale.h>)
LC_TIME该文件包含对日期和时间的格式化规则
LC_MESSAGES该目录下所含文件,针对肯定和否定(是/否)响应,就格式及数值做了规定

关于本表中的信息,还要注意以下几点。

  • 文件 LC_COLLATE 定义了一套规则,描述了如何在一字符集内对字符排序(例如alphabetical“按字母顺序排列的”字符集顺序)。这些规则将决定函数 strcoll(3)和strxfrm(3)的动作。即便是同属拉丁语系的语言,其遵循的排序规则也不相同。例如,一些欧洲语言有额外字母,在某些情况下排在字母 Z 之后。另外还有特殊情况,西班牙语的双字母序列 ll,排序时位于字母 l 之后。又比如德语的元音变音字符 ä,对应于ae,并与该双字母排在相同位置。
  • 目录 LC_MESSAGES 是程序显示信息迈向国际化的步骤之一。要实现更为全面的程序信息国际化,可以采用消息目录(参考 catopen(3)和 catgets(3)手册页)或是 GNU 的gettext API(参见 http://www.gnu.org/)。

10.4.2为程序设置地区

函数 setlocale()既可设置也可查询程序的当前地区。category 参数选择设置或查询地区的哪一部分,它仅能使用上表中列出的地区类别的常量名称。

char *setlocale(int category, const char *locale);		/* 成功返回一指向新的或者当前地区的字符串(通常是静态分配的)的指针,出错返回NuLL */

使用 setLocale()设置地区有两种不同的方法。locale 参数可能是一个字符串,指定系统上已定义的一个地区(例如,/usr /lib /locale 中的子目录的名称),如 de_DE 或 en_US。另外,地区可能被指定为空字符串,这意味着从环境变量取得地区的设置。setlocale(LC-ALL, "");

10.5 更新系统时钟

系统调用 settimeofday()是 gettimeofday()的逆向操作。它将 tv 指向 timeval 结构体里的秒数和微秒数,设置到系统的日历时间。

#include <sys/time.h>

int settimeofday(const struct timeval *tv, const struct timezone *tz);		/* 成功返回0,失败返回-1 */

和函数 gettimeofday()一样,tz 参数已被废弃,这个参数应该始终指定为 NULL。

settimeofday()调用所造成的那种系统时间的突然变化,可能会对依赖于系统时钟单调递增的应用造成有害的影响(例如,make(1),数据库系统使用的时间戳或包含时间戳记的日志文件)。出于这个原因,当对时间做微小调整时(几秒钟误差),通常是推荐使用库函数 adjtime(),它将系统时钟逐步调整到正确的时间。

#include <sys/time.h>

int adjtime(strucr timeval *delta, struct timeval *olddelta);		/* 成功返回0,失败返回-1 */

delta 参数指向一个 timeval 结构体,指定需要改变时间的秒和微秒数。如果这个值是正数,那么每秒系统时间都会额外拨快一点点,直到增加完所需的时间。如果 delta 值为负时,时钟以类似的方式减慢。

10.6 软件时钟(jiffies)

时间相关的各种系统调用的精度是受限于系统软件时钟(software clock)的分辨率,它的度量单位被称为 jiffies。jiffies 的大小是定义在内核源代码的常量 HZ。这是内核按照 round-robin 的分时调度算法分配 CPU 进程的单位。

10.7 进程时间

进程时间是进程创建后使用的 CPU 时间数量。出于记录的目的,内核把 CPU 时间分成以下两部分。

  • 用户 CPU 时间是在用户模式下执行所花费的时间数量。有时也称为虚拟时间(virtualtime),这对于程序来说,是它已经得到 CPU 的时间。

  • 系统 CPU 时间是在内核模式中执行所花费的时间数量。这是内核用于执行系统调用或代表程序执行的其他任务(例如,服务页错误)的时间。
    有时候,进程时间是指处理过程中所消耗的总 CPU 时间。
    当我们运行一个 shell 程序,我们可以使用的 time(1)命令,同时获得这两个部分的时间值,以及运行程序所需的实际时间。

vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ time ./show_time
real    0m0.003s
user    0m0.002s
sys     0m0.000s

系统调用 times(),检索进程时间信息,并把结果通过 buf 指向的结构体返回。

#include <sys/time.h>

clock_t times(struct tms *buf);		/* 成功返回自过去的任意点流逝的以时钟计时单元为单位的(真实的)时间,失败返回(clock_t)-1 */

buf 指向的 TMS 结构体有下列格式:

struct tms
{
    clock_t tms_utime;			/* 调用进程到目前为止使用的用户组件的 CPU 时间 */
    clock_t tms_stime;			/* 调用进程到目前为止使用的系统组件的 CPU 时间 */
    clock_t tms_cutime;			/* 父进程执行了系统调用 wait()的所有已经终止的子进程使用的用户组件的 CPU 时间 */
    clock_t tms_cstime;			/* 父进程执行了系统调用 wait()的所有已经终止的子进程使用的系统组件的 CPU 时间 */
};

数据类型 clock_t 是用时钟计时单元(clock tick)为单位度量时间的整型值,习惯用于计算 tms 结构体的 4 个字段。我们可以调用 sysconf(_SC_CLK_TCK)来获得每秒包含的时钟计时单元数,然后用这个数字除以 clock_t 转换为秒。

函数 clock()提供了一个简单的接口用于取得进程时间。它返回一个值描述了调用进程使用的总的 CPU 时间(包括用户和系统)。

#include <time.h>

clock_t clock(void);		/* 返回总的CPU时间,但计量单位是 CLOCKS_PER_SEC,必须除以这个值来获得进程
所使用的 CPU 时间秒数,失败返回(clock_t)-1 */

程序清单 :获取进程 CPU 时间

#include <sys/times.h>
#include <time.h>
#include "tlpi_hdr.h"

static void             /* Display 'msg' and process times */
displayProcessTimes(const char *msg)
{
    struct tms t;
    clock_t clockTime;
    static long clockTicks = 0;

    if (msg != NULL)
        printf("%s", msg);

    if (clockTicks == 0) {      /* Fetch clock ticks on first call */
        clockTicks = sysconf(_SC_CLK_TCK);
        if (clockTicks == -1)
            errExit("sysconf");
    }

    clockTime = clock();		/* 使用clock()获取进程时间 */
    if (clockTime == -1)
        errExit("clock");

    printf("        clock() returns: %ld clocks-per-sec (%.2f secs)\n",
            (long) clockTime, (double) clockTime / CLOCKS_PER_SEC);

    if (times(&t) == -1)		/* 使用times()获取进程时间 */
        errExit("times");
    printf("        times() yields: user CPU=%.2f; system CPU: %.2f\n",
            (double) t.tms_utime / clockTicks,
            (double) t.tms_stime / clockTicks);
}

int
main(int argc, char *argv[])
{
    int numCalls, j;

    printf("CLOCKS_PER_SEC=%ld  sysconf(_SC_CLK_TCK)=%ld\n\n",
            (long) CLOCKS_PER_SEC, sysconf(_SC_CLK_TCK));

    displayProcessTimes("At program start:\n");

    numCalls = (argc > 1) ? getInt(argv[1], GN_GT_0, "num-calls") : 100000000;
    for (j = 0; j < numCalls; j++)
        (void) getppid();

    displayProcessTimes("After getppid() loop:\n");

    exit(EXIT_SUCCESS);
}
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/time$ ./process_time 100000000
CLOCKS_PER_SEC=1000000  sysconf(_SC_CLK_TCK)=100

At program start:
        clock() returns: 608 clocks-per-sec (0.00 secs)
        times() yields: user CPU=0.00; system CPU: 0.00
After getppid() loop:
        clock() returns: 4778275 clocks-per-sec (4.78 secs)
        times() yields: user CPU=2.15; system CPU: 2.62
  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值