![Linux程序设计(第4版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/825/26211825/b_26211825.jpg)
4.8 资源和限制
Linux系统上运行的程序会受到资源限制的影响。它们可能是硬件方面的物理性限制(例如内存)、系统策略的限制(例如,允许使用的CPU时间)或具体实现的限制(如整数的长度或文件名中所允许的最大字符数)。UNIX规范定义了一些可由应用程序决定的限制。第7章对限制及突破限制的后果做了进一步讨论。
头文件limits.h中定义了许多代表操作系统方面限制的显式常量,如表4-8所示。
表4-8
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0158_0002.jpg?sign=1739386416-ocpHe5lbWPdHwl1XQwq7NYXKn88vaFvI-0-2ea03fa8fc32871fa48967df64869c27)
还有许多其他对应用程序有用的限制,请参考你自己系统中的头文件。
注意:NAME_MAX是特定于文件系统的。为了写可移植性更好的代码,你应该使用pathconf函数。详细信息请参考pathconf的手册页。
头文件sys/resource.h提供了资源操作方面的定义,其中包括对程序长度、执行优先级和文件资源等方面限制进行查询和设置的函数:
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0158_0003.jpg?sign=1739386416-ELLswYqdoCnc6G79biJlF3pbBsEmehcW-0-bb495a2aab689e715b805472856d0916)
id_t是一个整数类型,它用于用户和组标识符。在头文件sys/resource.h中定义的rusage结构用来确定当前程序已耗费了多少CPU时间,它至少包含表4-9所示的两个成员。
表4-9
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0158_0004.jpg?sign=1739386416-EzRVTmK2nM2SqfrHCUKO72l35eVVIOpB-0-98ab05096b293ad4a7147d8b883a7bfd)
timeval结构定义在头文件sys/time.h中,它包含成员tv_sec和tv_usec,分别代表秒和微秒。
一个程序耗费的CPU时间可分为用户时间(程序执行自身的指令所耗费的时间)和系统时间(操作系统为程序执行所耗费的时间,即执行输入输出操作的系统调用或其他系统函数所花费的时间)。
getrusage函数将CPU时间信息写入参数r_usage指向的rusage结构中。参数who可以是表4-10所示的常量之一。
表4-10
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0159_0001.jpg?sign=1739386416-wV2DPFAP5Euxp7KDxsfZBuJxbJgEgfoo-0-e29eb9b95bf80008d0d871ee937cab2d)
我们将在第11章讨论子进程和任务优先级,但考虑到完整性,我们将在这里简单介绍它们对系统资源的影响。就现在而言,了解下面一点就够了:每个运行的程序都有一个与之关联的优先级,优先级越高的程序将分配到更多的CPU可用时间。
普通用户只能降低其程序的优先级,而不能升高。
应用程序可以用getpriority和setpriority函数确定和更改它们(和其他程序)的优先级。被优先级函数检查或更改的进程可以用进程标识符、组标识符或用户来确定。which参数指定了对待who参数的方式,如表4-11所示。
表4-11
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0159_0002.jpg?sign=1739386416-3ouI2b62gezji2q6HUGOjEb8KFHY29mZ-0-3347b6b5fe12e6dba26d8928bd05539e)
因此,为确定当前进程的优先级,你可以调用:
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0159_0003.jpg?sign=1739386416-hL9drSPnkP8NUNXOnBsA35mPkJTQkEAn-0-a5ae8f96f8e877204c658139886b16cc)
setpriority函数用于设置一个新的优先级(如果可能的话)。
默认的优先级是0。正数优先级用于后台任务,它们只在没有其他更高优先级的任务准备运行时才执行。负数优先级使一个程序运行更频繁,获得更多的CPU可用时间。优先级的有效范围是-20~+20。这很容易让人困惑,因为数值越高,执行优先级反而越低。
getpriority在成功时返回一个有效的优先级,失败时返回-1并设置errno变量。因为-1本身是一个有效的优先级,所以在调用getpriority之前应将errno设置为0,并在函数返回时检查它是否仍为0。setpriority在成功返回0,否则返回-1。
系统资源方面的限制可以通过getrlimit和setrlimit来读取和设置。这两个函数都利用一个通用结构rlimit来描述资源限制。该结构定义在头文件sys/resource.h中,它包含表4-12所示的成员。
表4-12
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0159_0004.jpg?sign=1739386416-h1t2Y6xOtO2DyrSQ7U6faN1dB9Yhhn7G-0-46950c345638e918a2df0a107921ed12)
类型rlim_t是一个整数类型,它用来描述资源级别。一般来说,软限制是一个建议性的最好不要超越的限制,如果超越可能会导致库函数返回错误。硬限制如果被超越,则可能会导致系统通过发送信号的方式来终止程序的运行。例如,当CPU时间限制被超越时系统会发送SIGXCPU信号,数据长度限制被超越时系统会发送SIGSEGV信号。程序可以把自己的软限制设置为小于硬限制的任何值。它也可以减小自己的硬限制。但只有以超级用户权限运行的程序才能增加硬限制。
有许多系统资源可以进行限制,它们由rlimit函数中的resource参数指定,并在头文件sys/resource.h中定义,如表4-13所示。
表4-13
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0160_0001.jpg?sign=1739386416-WFe7ljAJFXw1UhPLqIyP6mRY7j9olwKt-0-1824e0e42086c4508d6862a2f7e512de)
下面的实验给出了一个程序limits.c,它模拟一个典型的应用程序。该程序设置并超越了一个资源限制。
实验 资源限制
(1)首先,把你在程序中要用到的所有函数对应的头文件包含进来:
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0160_0002.jpg?sign=1739386416-lGZYhquJ4aqfQe4Ln1HXZufQdlUoi23F-0-08a125b9a0b71edc6ddaa3e223858e10)
(2)void work( )函数将一个字符串写入一个临时文件10000次,然后做一些算术运算以产生CPU负载:
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0160_0003.jpg?sign=1739386416-BzkzePRnqPQP1DAsQKYsDTUO6Rr8Kdw7-0-fb07c9e98894db69d39215d795c4ba72)
(3)main函数调用work函数,然后用getrusage函数来发现它耗费的CPU时间,并把该信息显示在屏幕上:
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0161_0002.jpg?sign=1739386416-2kadxw0UPppg8kfSOzG2pdq8XQ7Pn683-0-0e2052fe9ba1693c582ad9ac0eb7fafa)
(4)接着,main函数分别调用getpriority和getrlimit来发现它的当前优先级和文件大小限制:
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0161_0003.jpg?sign=1739386416-WfXW4lbpLlVxhfAfG0NBynnuSKOQzMFe-0-8638c64d303ca4632ee2fa675bff3641)
(5)最后,我们用setrlimit设置文件大小限制并再次调用work,这次work函数的执行会失败,因为它试图创建一个太大的文件:
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0161_0004.jpg?sign=1739386416-9p3bXPbEvlBJe5z1vjc064GGmpucqFkF-0-a7c7860e21497e295bc96d8fc073e3cf)
当运行这个程序时,你可以看到消耗的CPU资源有多少以及程序运行的默认优先级。一旦设置了文件大小限制,程序就不能往临时文件里写入多于2048个字节了。
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0161_0005.jpg?sign=1739386416-7tfLEBespPnbzWEXTx8dHJh85DuVRvZF-0-05e810605876653035f436e37b68ae95)
你可以用nice命令启动程序来改变程序的优先级。这里,你看到程序的优先级变成了+10。因此,程序的执行时间变长了。
![](https://epubservercos.yuewen.com/08DD0E/14642180305205206/epubprivate/OEBPS/Images/figure_0162_0001.jpg?sign=1739386416-15QaGxFCI9YbMYqfJBJ1JURlpd6fWMfo-0-eb19958c9916732b7d59172d813c65c6)
实验解析
limits程序通过调用work函数来模拟一个典型程序的行为。它执行一些运算并产生一些输出,在本例中,它输出大约150K字节的数据到临时文件。它调用资源函数来发现其优先级和文件大小限制。在本例中,文件大小限制未设置,所以你想创建多大的文件就可以创建多大的文件(只要磁盘空间允许)。随后,程序设置它的文件大小限制为2K并再次执行一些工作。此时,work函数的调用失败了,因为它不能创建太大的临时文件。
你也可以通过bash的ulimit命令为在某一特定shell中运行的程序设置限制。
在本例中,出错信息Error writing to temporary file(写临时文件出错)可能不会像你期望的那样打印出来。这是因为当资源限制被超越时,一些系统(如Linux 2.2和后续版本)会通过发送信号SIGXFSZ的方式来终止程序。你将在第11章学习有关信号及其使用的更多知识。其他一些POSIX兼容的系统可能只是让资源限制被超越的函数返回一个错误。