linux限制资源使用率,Linux环境下
运行在Linux系统上的程序资源有限。这些限制可能是由硬件(例如,内存)、系统策略(例如,允许的CPU时间)或实现限制(例如,整数的大小或文件名中允许的最大字符数)引起的。Unix规范定义了一些可以由程序决定的限制。我们将在第七章进行更深入的讨论。
limits.h头文件定义了许多表示操作系统限制的常量。它们包括:
受限的持续使用
NAME_MAX文件名中的最大字符数
字符值的位数
最大CHAR_MAX字符值
INT_MAX最大INT值
程序还可以使用许多其他限制。要了解更详细的信息,我们可以检查我们安装的头文件。
注意:NAME_MAX依赖于文件系统。对于更易移植的代码,我们应该使用pathconf函数。我们可以查看pathconf的手册页以获得更多详细信息。
头文件sys/resource.h提供了资源操作的定义。它们包括确定和设置程序允许大小、执行优先级和文件限制的函数。
#包含sys/resource.h
int getpriority(int which,id _ t who);
int setpriority(int which,id_t who,int priority);
int getrlimit(int resource,struct rlimit * r _ limit);
int setrlimit(int resource,const struct r limit * r _ limit);
int getrusage(int who,struct ru sage * r _ usage);
Id_t是用于组和用户标识的整数类型。rusage结构在sys/resource.h文件中定义,用于确定当前程序使用了多少CPU时间。他必须至少拥有以下成员:
Rusage成员描述
结构timeval ru_utime使用的用户时间
结构timeval ru_stime使用的系统时间
Timeval结构在sys/time.h文件中定义,包含分别代表秒和微秒的tv_sev和tv_usec字段。
一个程序消耗的CPU时间分为用户时间(程序本身执行自己的指令所花费的时间)和系统时间(操作系统执行程序所花费的时间);也就是说,执行输入输出系统调用或其他系统功能所花费的时间)。
Getrusage函数将CPU时间信息写入参数r_usage指向的rusage结构中。who参数可以是下列常量之一:
世卫组织不断描述
RUSAGE_SELF只返回当前程序的使用情况。
RUSAGE_CHILDREN还包含子进程的使用信息。
我们将在第11章中讨论子流程和任务优先级,但为了完整起见,我们将在这里讨论它们所涉及的系统资源。现在,我们可以说每个正在运行的程序都有一个与之相关联的优先级,优先级高的程序将被分配更多的可用CPU时间。
程序可以使用getpriority和setpriority函数来确定和修改它们的优先级。要检测或更改其优先级的进程可以通过进程标识符、组标识符或用户来标识。哪个参数指示如何处理who参数。
哪个参数描述
o _ process是一个进程标识符。
O _ pgrp是一个进程组。
O _ user是一个用户标识符。
所以,要确定当前进程的标识符,我们可以调用下面的函数:
priority=get priority(PRIO _进程,getpid());
如果可能,setpriority功能将允许设置新的优先级。
的默认优先级为0。正优先级用于当没有更高优先级的任务准备好运行时运行的后台任务。负优先级将使程序运行更频繁,并占用更多的可用CPU时间。可用的优先级范围是-20到20。这常常令人困惑。数值越高,执行的优先级越低。
如果成功,Getpriority将返回正确的优先级,如果失败,将返回-1,并设置errno变量。因为-1本身就是一个可用的优先级,所以在调用getpriority之前应该将errno设置为0,并检查函数返回时是否仍然为0。如果成功,setpriority函数将返回0;否则,它将返回-1。
系统资源的限制可以通过getrlimit和setrlimit函数读取和设置。这两个函数都使用通用结构rlimit来描述资源约束。它在sys/resource.h中定义,包含下列成员:
Rlimit成员描述
Rlim _ ttrim _ cur当前软限制
Rlim_t rlim_max硬限制
Rlim_t是一个整数类型,用于描述资源级别。通常,软限制是不应超过的建议限制;如果这样做,库函数将返回一个错误。如果超过硬限制,系统可能会尝试向其程序发送消息以终止其操作。例如SIGXCPU信号超过CPU时间,SIGSEGV信号超过数据大小限制。程序可以将其软限制设置为任何小于其硬限制的值,也可以降低其硬限制。只有以超级权限运行的程序才能增加硬限制。
有许多系统资源是有限的。这是由rlimit函数的资源参数指定的。它们在sys/resource.h中定义,描述如下:
参数描述
RLIMIT_CORE核心副本文件大小(字节)
RLIMIT_CPU CPU时间限制(秒)
RLIMIT_DATA的数据()段限制(以字节为单位)
RLIMIT_FSIZE文件大小限制(字节)
RLIMIT_NOFILE可以打开的文件数量的限制
RLIMIT_STACK的堆栈大小限制(以字节为单位)
RLIMIT_AS(堆栈和数据)的地址空间限制(字节)
下面的实验部分演示了一个程序limits.c,用来模拟一个通用程序。同时,他设定并突破了资源限制。
实验资源限制
1包含我们程序中使用的所有函数所需的头文件:
#包含sys/types.h
#包含sys/resource.h
#包含系统/时间. h
#包括unistd.h
#包含stdio.h
#包含数学. h
2工作函数将一个字符串写入临时文件10,000次,然后执行一些算术运算,在CPU上生成一个负载:
无效工作()
文件* f;
int I;
双x=4.5
f=tmpfile();
for(I=0;我10000;i ) {
fprintf(f," Do some output/n ");
if(ferror(f)) {
fprintf(stderr,"写入临时文件时出错/n ");
出口(1);
}
}
for(I=0;我1000000;我)
x=log(x * x 3.21);
main函数调用work函数,然后使用getrusage函数计算他已经使用了多少CPU时间。他将在屏幕上显示以下信息:
int main()
struct rusage r _ usage
struct rlimit r _ limit
int优先级;
work();
getrusage(RUSAGE_SELF,r _ usage);
printf("CPU使用率:用户=%ld.ld,系统=%ld.ld/n ",
r_usage.ru_utime.tv_sec,r_usage.ru_utime.tv_usec,
r_usage.ru_stime.tv_sec,r _ usage . ru _ stime . TV _ usec);
4接下来,他将调用getpriority函数和getrlimit函数分别检查当前级别和文件大小限制:
priority=get priority(PRIO _进程,getpid());
printf("当前优先级=%d/n ",优先级);
getrlimit(RLIMIT_FSIZE,r _ limit);
printf("当前FSIZE限制:软=%ld,硬=%ld/n ",
r_limit.rlim_cur,r _ limit . rlim _ max);
5.最后,我们使用setrlimit函数设置文件大小限制,并再次调用work函数,这将失败,因为他试图创建一个太大的文件:
r _ limit.rlim _ cur=2048
r _ limit.rlim _ max=4096
printf("设置2K文件大小限制/n ");
setrlimit(RLIMIT_FSIZE,r _ limit);
work();
退出(0);
当我们运行这个程序时,我们会看到它消耗了多少CPU时间,以及程序运行的默认优先级。一旦设置了文件大小限制,该程序就不能向临时文件中写入大于2048字节的内容。
$ cc -o限额限额. c -lm
$ ./限制
CPU使用率:用户=0.980000,系统=0.010000
当前优先级=0
当前FSIZE限制:软=-1,硬=-1
设置2K文件大小限制
超过文件大小限制
我们可以通过用nice命令启动程序来改变它的优先级。这里,我们将程序的优先级改为10。因此,系统将花费更长的时间来执行该程序:
很好。/限制
CPU使用率:用户=1.000000,系统=0.000000
当前优先级=10
当前FSIZE限制:软=-1,硬=-1
设置2K文件大小限制
超过文件大小限制
极限程序调用工作函数来模拟通常的程序行为。他将执行一些计算并产生一些输出。在本例中,大约150K的内容被写入临时文件。他调用资源函数来检查它的优先级和文件大小限制。在本例中,没有设置文件大小限制,这允许我们创建所需大小的文件。然后,程序将其文件大小限制为2K,并尝试再次执行工作函数。这一次,work函数将失败,因为它无法创建如此大的临时文件。
注意:您还可以使用特定shell的ulimit命令来设置程序运行的限制。
在本例中,错误消息“写入临时文件时出错”可能不会如我们预期的那样显示。这是因为当程序超出资源限制时,一些系统会终止程序的执行。这是通过发送SIGXFSZ信号来实现的。我们将在第11章学习更多关于信号和如何使用它们的知识。其他POSIX系统可能只是让超出限制的函数返回一个错误。
在本章中,我们学习了Linux环境,并测试了程序运行的条件。我们讨论了命令行参数和环境变量,它们都可以用来改变程序的默认行为并提供有用的程序选项。
我们还了解了程序如何使用库函数来操作日期和时间值,并获得自己的信息,以及运行它的用户和主机的信息。
Linux程序通常需要共享精确的资源,所以我们也讨论如何确定和管理这些程序。