时间与系统限制

时间与系统限制

时间

本文是作者阅读TLPI(The Linux Programer Interface的总结),为了突出重点,避免一刀砍,我不会过多的去介绍基本的概念和用法,我重点会去介绍原理和细节。因此对于本文的读者,至少要求读过APUE,或者是实际有写过相关代码的程序员,因为知识有点零散,所以我会尽可能以FAQ的形式呈现给读者。

时间有哪些类型?

对于一个程序来说,主要关注下面两种时间类型:

  • 真实时间: 度量这个时间的起点有两个: 一为某个标准点也就是日历时间,适用于需要对数据库记录或文件打时间戳,二为进程生命周期内的某个固定时点,后者为流逝时间或者墙上时间。主要针对需要周期性操作或定期从外部输入设备进行度量的程序。

  • 进程时间: 一个进程所使用的CPU时间总量,适用于对程序、算法性能的检查或优化。

大多数计算机体系结构都内置有硬件时钟,使得内核得以计算真实时间和进程时间。

什么是日历时间?

日历时间存储类型为time_t的变量中,是自Epoch以来的秒数来度量的,Epoch亦即通用协调时间(UTC)的1970年1月1日早晨零点。通过如下API获得:

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

Linux最早的时候只提供了time用于求日历时间,但是因为其精度问题,后来又引入了gettimeofday这个系统调用,此时time系统调用就显得多余了,因此就将time实现为调用gettimeofday的一个库函数。

       #include <sys/time.h>
       int gettimeofday(struct timeval *tv, struct timezone *tz);
       struct timeval {
           time_t      tv_sec;     /* seconds */
           suseconds_t tv_usec;    /* microseconds */
       };

如何将time_t转换为可打印格式?

       char *ctime(const time_t *timep);
       char *ctime_r(const time_t *timep, char *buf);   //可重入版本

通过ctime将time_t的类型的数据转换为可打印的字符串,其打印的格式为:"Wed Jun 30 21:49:08 1993\n",没有办法定制这个时间的格式,只能通过字符串截取来获取其中的部分字符串来使用。

如何将time_t转换为分解时间?

Linux下通过struct tm这个结构用于表示分解时间:

   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 */
   };

通过下列API可用于将time_t转换为分解时间。

       #include <time.h>

       struct tm *gmtime(const time_t *timep);
       struct tm *gmtime_r(const time_t *timep, struct tm *result);

       struct tm *localtime(const time_t *timep);
       struct tm *localtime_r(const time_t *timep, struct tm *result);

gmtime和localtime的区别就在于,后者会考虑到时区和夏令时,会返回一个对应于系统本地时间的一个分解时间。

如何将分解时间转换为time_t呢?

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

注: mktime可能会修改timeptr所指向的结构体,mktime不要求tm结构体的字段都在指定范围的限制中,任何一个字段的值超出了范围,mktime都会将其调整回有效范围内。

如何将分解时间转换为可打印格式的时间?

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

如何定制时间的输出格式?

       #include <time.h>

       size_t strftime(char *s, size_t max, const char *format,
                       const struct tm *tm);
       #define _XOPEN_SOURCE       /* See feature_test_macros(7) */
       #include <time.h>
       char *strptime(const char *s, const char *format, struct tm *tm);

strftime是将分解时间转换成指定的格式的字符串,strptime则是将指定格式的字符串,转换为分解时间。

时间API

如何在程序中操作时区?

不同的国家使用不同的时区和夏时制,对于要输入和输出时间的程序来说,必须要对系统所处的时区和夏时制加以考虑。时间信息往往既浩繁又多变,出于这个原因,系统没有将其直接编码于程序或函数库中,而是以标准格式保存于文件中,并加以维护。这些文件都放在/usr/share/zoneinfo目录下,该目录下的每个文件都包含了一个特定国家或地区内时区制度相关信息。系统的本地时间由/etc/localtime时区文件定义,通常链接到/usr/share/zoneinfo目录中的某个时区文件。因此如果要更改时区,只需要重新链接/etc/localtime/usr/share/zoneinfo目录中正确的时区文件即可。这些操作都是直接通过命令行即可完成,那么如何在程序中指定时区呢?如果是一个运行中的程序可以通过设置TZ环境变量来给运行中的程序指定一个时区。TZ环境变量的值的格式为:时区名称,时区名称可以参考/usr/share/zoneinfo目录下的文件名。

注:时区文件的格式可以通过man 5 tzfile查看到,可以通过man 8 zic命令来创建时区文件,此外man 8 zdump可以更具指定时区文件来显示当前时间

如何在外部改变程序的时区?

在执行程序的时候传递环境变量TZ可以控制程序的时区,其原理是因为程序在调用localtime/mktime/strftime这类方法的时候,其实内部会通过tzset来设置时区信息,该方法在设置时区信息的时候会去寻找TZ环境变量,如果设置了,就把时区设置为TZ环境变量所指定的时区,否则就设置为/etc/localtime所指的时区。而tzset内部通过解析时区文件,然后将解析出来的时区信息赋值给下面这几个全局的变量。

 extern char *tzname[2];   
 extern long timezone;      
 extern int daylight;      

如何获取进程时间?

在谈时间类型的时候,说过有两种类型的时间,一种就是真实时间,另一种就是进程时间,记录了进程使用CPU的时间数量,linux下通过struct tms结构来表示:

           struct tms {
               clock_t tms_utime;  /* user time */
               clock_t tms_stime;  /* system time */
               clock_t tms_cutime; /* user time of children */
               clock_t tms_cstime; /* system time of children */
           };

为了获取进程时间,linux提供了times系统调用,其函数声明如下:

       #include <sys/times.h>
       clock_t times(struct tms *buf);

times返回的是clock_t类型的,这是一个用时钟计时单元为单位度量的类型,通过sysconf(_SC_CLK_TCK),可以获取每秒包含的时钟计时单元,最后就可以换算为秒。除了times外,还有一个clock系统调用,可以获取进程总的CPU时间:

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

clock返回的也是clock_t类型的,但是和times不同的是,clock返回的计量单位是CLOCKS_PER_SEC,通常这个值是一个常量10000,times和clock采用了两种不同的计量单位,这是历史原因导致的。

系统限制和选项

但凡UNIX实现,都会对各种系统特性和资源加以限制,并提供各种标准所定义的选项,例如:

  • 一个进程能够同时拥有多少已打开的文件
  • 系统是否支持实时信号
  • int类型变量可存储的最大值是多少
  • 一个程序的参数列表能有多大
  • 路径名的最大长度是多少

尽管可以把假定的限制和选项硬性写入程序编码,但这将破坏程序的可移植性,因为限制和选项可能会有所不同。因此C语言标准和SUSv3为此提供了两种重要的途径来获取限制和选项。

  • 在编译程序时能够获得一些限制和选项,比如int类型的最大值,此类限制可在头文件中记录。
  • 另外一些限制和选项在程序运行时可能会有所变化,为此定义了sysconf pathconf fpathconf提供给应用程序调用以检查系统实现的限制和选项。

如何在shell中获取限制和选项?

       getconf system_var
       getconf path_var pathname

[root@localhost ~]# getconf NAME_MAX /boot
255
[root@localhost ~]# getconf ARG_MAX
2097152

getconf可以获取系统限制,也可以获取文件相关限制,因为不同的文件系统限制不同,所以文件限制多了一个参数,用来表明是哪个文件系统。

如何在运行时获取系统限制?

       #include <unistd.h>
       long sysconf(int name);

可以通过man 7 posixoptionsman sysconf来查看支持的name值.在某些系统调用的man文档中你也可以找到一些name值,用于获取和这个系统调用相关的限制。

如何在运行时获取与文件相关的限制?

       #include <unistd.h>

       long fpathconf(int fd, int name);
       long pathconf(char *path, int name);

与文件相关的限制,都是两个参数,一个是要获取限制的选项名称,另一个就是相关的一个文件,因为对文件限制来说,不同的文件系统限制值不同。因此需要指定一个文件来指明要获取的限制是针对哪个文件系统的。

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值