|
运行在 linux系统上的程序受到(be subject to)资源的限制.这可能是硬件方面的无理性限制(如内存),或者是系统策略方面的限制(例如所分配到的CPU时间),还可以是软件实现(implementation)方面的限制(如一个整数的长度或者文就名所允许的最大字符长度).UNIX 技术规范(specification)定义这些限制,可以由一个应用程序测定出来。
头文件 limits.h 定义了许多一目了然(manifest)的常数,它们是一些操作系统方面的限制值:
Limit Constant Purpose
NAME_MAX 文件名所允许用的最大字符数
CHAR_BIT 一个char类型值的最大位数
CHAR_MAX char类型的最大值
INT_MAX int 类型的最大值
注意,NAME_MAX 是与文件系统特定的。基于代码的可移植性考虑,应该使用 pathconf() 函数,详见参考手测。
sys/resource.h 头文件提供了资源操作方面的定义。其中包括对程序的最大长度,执行优先级以及文件资源进行核查和设置限制的函数:
#include <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 rlimit *r_limit);
int getrusage(int who, struct rusage *r_usage);
id_t 是一个用在用户标识符和组标识符方面的整数类型。rusage 结构体,定义在 sys/resource.h 中,它用在确定当前程序使用了多少的 CPU 时间。它必须至少包含以下2个成员:
rusage Member Description
struct timeval ru_utime 用户占用的时间
struct timeval ru_stime 系统占用的时间
timeval 结构体定义在 sys/time.h 中并且包含 tv_sec 和 tv_usec 两个域,分别代表着秒和微秒。
被一个程序消耗的 CPU 时间分为用户时间(user time)和系统时间(system time).用户时间是用户执行自身指令所消耗的时间;系统时间由操作系统为了这个程序而消耗的时间--在系统调用中完成输入输出或者执行其他系统函数所花费的时间。
getrusage() 函数把 CPU 时间信息写到由 r_usage 参数指向的 rusage 结构体中。who 参数可以为以下常数中的一个:
who Constant Description
RUSAGE_SELF 只返回当前程序的CPU时间占用信息
RUSAGE_CHILDREN 还包含子进程的 CPU 占用时间
简单的说,每一个运行着的程序都有一个与之相关联的优先级,高优先级的程序会被分配到更多的 CPU 时间。普通用户只能降低他们程序的优先级,而不能增加它们。
程序可以通过 getpriority() 和 setpriority() 函数确定和改变他们的优先级或者其他人的优先级。被优先级处理函数检查或改变的进程可以由进程标识符,组标识符,或用户名来得到区分。which 参数说明了 who 参数被对待的方式:
which 参数 描述
PRIO_PROCESS who 是一个进程标识符
PRIO_PGRP who 是一个进程分组标识符
PRIO_USER who 是一个用户标识符
所以,确定一个当前进程的优先级,可以如下调用:priority = getpriority(PRIO_PROCESS, getpid());
setpriority() 函数允许设置一个新的优先级,如果可能的话。
默认的优先级是 0. 正优先级用用于后台任务,它们当没有其他更高优先级准备运行时才会运行。负优先级会使程序运行的更加频繁,且分配了更大一块的 CPU 时间。可用的优先级范围从 -20 到 +20。这经常使人迷惑,因为更高的优先级数字竟然是对应着更低的执行优先权。
getpriority() 函数在成功时返回一个有效的优先级,否则返回 -1 并设置 errno 变量(with errno set on error 并以 errno 确定错误类型)。因为 -1 它自己也是一个有效的优先级,所以 errno 变量应该在调用 getpriority() 前设置为 0 ,并在返回时检查它是否仍为 0。setpriority() 如果成功则返回0,否则返回 -1.
通过 getrlimit() 和 setrlimit() 函数可以读取与设置系统的限制性资源。这两个函数都要用 rlimit 结构体来描述资源方面的限制。这个结构体定义在 sys/resource.h 里,它有以下成员:
rlimit Member Description
rlim_t rlim_cur 当前的软限制
rlim_t rlim_max 硬限制
定义类型 rlim_t 是一个用来描述资源容量(resource levels)的整数类型。典型地,软限制是一个带有忠告性质的限制值,最好不要超过它,否则可能会引起库函数返回错误。硬限制,如果超出,就会引起系统终止程序的运行,办法是给程序发出一个信号。例如,超出 CPU 时间限制时发送的是 SIGXCPU 信号;超出某个数据容量限制时发出 SIGSEGV 信号。一个程序可以设置它自己的软限制值为小于硬限制值的任意值。它可以减少自己的硬限制。只有以超级用户权限运行的程序才可以增加硬限制。
一些系统资源可以被限制。这些由 rlimit() 函数的 resource 参数所指定并且定义在 sys/resource.h 头文件中,如下所示:
resource Parameter Description
RLIMIT_CORE core 文件的最大字节数,若其值为0则阻止创建core文件
RLIMIT_CPU CPU 时间的最大量值(秒),当超过此软限制时,向该进程发送SIGXCPU信号
RLIMIT_DATA 数据段的最大字节长度,是初始化数据,非初始化数据以堆的综合
RLIMIT_FSIZE 可以创建的文件的最大字节长度,当超过此软限制时,则向该进程发送 SIGXFSZ 信号
RLIMIT_NOFILE 每个进程能打开的最大文件数,更改此限制将影响sysconf函数在参数_SC_OPEN_MAX中的返回值。
RLIMIT_STACK 栈的最大字节长度
RLIMIT_AS 进程可用存储区的最大总长度(字节),这会影响 sbrk()和mmap()函数
RLIMIT_NPROC 每个实际用户ID可拥有的最大子进程数,更改此限制会影响sysconf函数在参数_SC_CHILD_MAX中的返回值。
RLIMIT_RSS 最大驻内存集的字节长度(resident set size in bytes,RSS)
RLIMIT_PTPRIO 最大的实时优先级
RLIMIT_NICE 非实时进程的优先级(nice level)
RLIMIT_MEMLOCK 一个进程使用 mlock 函数能够锁定在存储器中的最大字节长度
RLIMIT_MSGQUEUE 信息队列的最大数目
RLIMIT_SIGPENDING 待决信号的最大数目
RLIMIT_LOCKS 文件锁的最大数目
测试代码:
01 #include <sys/types.h>
02 #include <sys/resource.h>
03 #include <sys/time.h>
04 #include <unistd.h>
05 #include <stdio.h>
06 #include <stdlib.h>
07 #include <math.h>
08
09 void work()
10 {
11 FILE *f;
12 int i;
13 double x = 4.5;
14
15 f = tmpfile();
16
17 for(i = 0; i < 10000; i++) {
18 fprintf(f, "Do some output\n");
19 if(ferror(f)) {
20 fprintf(stderr, "Error writing to temporary file\n");
21 exit(1);
22 }
23 }
24
25 for(i = 0; i < 1000000; i++)
26 x = log(x*x + 3.21);
27 }
28
29 int main()
30 {
31 struct rusage r_usage;
32 struct rlimit r_limit;
33 int priority;
34
35 work();
36 getrusage(RUSAGE_SELF, &r_usage);
37
38 printf("CPU usage: User = %ld.%06ld, System = %ld.%06ld\n",
39 r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec,
40 r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
41
42 priority = getpriority(PRIO_PROCESS, getpid());
43 printf("Current priority = %d\n", priority);
44
45 getrlimit(RLIMIT_FSIZE, &r_limit);
46 printf("Current FSIZE limit: soft = %ld, hard = %ld\n",
47 r_limit.rlim_cur, r_limit.rlim_max);
48
49 r_limit.rlim_cur = 2048;
50 r_limit.rlim_max = 4096;
51 printf("Setting a 2K fil size limit\n");
52 setrlimit(RLIMIT_FSIZE, &r_limit);
53
54 work();
55 exit(0);
56 } 运行输出 1:[root@localhost C]# ./resource_limits.exe
CPU usage: User = 0.108006, System = 0.000000
Current priority = 0
Current FSIZE limit: soft = -1, hard = -1
Setting a 2K fil size limit
File size limit exceeded 运行输出 2:[root@localhost C]# nice ./resource_limits.exe
CPU usage: User = 0.124007, System = 0.000000
Current priority = 10
Current FSIZE limit: soft = -1, hard = -1
Setting a 2K fil size limit
File size limit exceeded 程序分析:
15) tmpfile() 函数创建一个临时文件,并返回一个文件流到 f
18) 写一万句 Do some output
19-21)出错输出然后退出
36) 调用 getrusage(RUSAGE_SELF, &r_usage); 函数。参数 RUSAGE_SELF 表示只返回当前程序的CPU占用时间信息,&r_usage 参数传入 r_usage 结构体指针(自身地址),这样 getrusage() 函数得到的 CPU 时间信息就会写到 r_usage 中
38-40) 打印出用户的CPU时间和系统的CPU时间
42) 利用 getpriority(PRIO_PROCESS, getpid()) 函数得到进程标识符
45) 利用 getrlimit(RLIMIT_FSIZE, &r_limit) 函数得到文件长度限制信息。这里的文件长度信息没有设置,所以允许你创建一个你希望的任意大的文件(当然需要硬盘空间的允许)。所以这里返回的是 -1.
52) 设置可以操作的文件长度限制在 2K
54) 这样,再调用 work() 函数时,因为要创建 150k 的文件,所以发生失败。
注意的是,上面的程序中,'Error writing to temporary file' 这句话不会如你期望的打印出来。这是因为一些系统(如 linux2.2 及以后的版本)当超出资源限制时会终止程序---这通过发送一个 SIGXFSZ 的信号来实现。
更改资源限制时,必须遵循以下三条规则:
1. 任何一个进程都可将一个软限制值更改为更小或等于其硬限制值。
2. 任何一个进程都可以降低其硬限制值,但它必须大于或等于软限制值。这种降低对普通用户而言是不可逆的。
3. 只有超级用户进程可以提高硬限制值。
常量 RLIM_INFINITY 指定了一个无限量的限制。
下面代码打印当前资源限制:
[C++] 纯文本查看 复制代码 #include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#define doit(name) pr_limits(#name, name)
static void pr_limits (char *, int);
int main(void)
{
#ifdef RLIMIT_AS
doit(RLIMIT_AS);
#endif
doit(RLIMIT_CORE);
doit(RLIMIT_CPU);
doit(RLIMIT_DATA);
doit(RLIMIT_FSIZE);
#ifdef RLIMIT_LOCKS
doit(RLIMIT_LOCKS);
#endif
#ifdef RLIMIT_MEMLOCK
doit(RLIMIT_MEMLOCK);
#endif
doit(RLIMIT_NOFILE);
#ifdef RLIMIT_NPROC
doit(RLIMIT_NPROC);
#endif
#ifdef RLIMIT_RSS
doit(RLIMIT_RSS);
#endif
#ifdef RLIMIT_SBSIZE
doit(RLIMIT_SBSIZE);
#endif
doit(RLIMIT_STACK);
#ifdef RLIMIT_VMEM
doit(RLIMIT_VMEM);
#endif
exit(0);
}
static void pr_limits(char *name, int resource)
{
struct rlimit limit;
if(getrlimit(resource, &limit) < 0) {
perror ("getrlimit");
exit (EXIT_FAILURE);
}
printf ("%-14s ", name);
if (limit.rlim_cur == RLIM_INFINITY)
printf ("(infinite) ");
else
printf ("%10lld ", limit.rlim_cur);
if (limit.rlim_max == RLIM_INFINITY)
printf ("%10lld ", limit.rlim_max);
putchar ((int)'\n');
}
运行输出:[beyes@localhost libfunc]$ ./printlimit
RLIMIT_AS (infinite) 8589934591
RLIMIT_CORE 4294967296 8589934591
RLIMIT_CPU (infinite) 8589934591
RLIMIT_DATA (infinite) 8589934591
RLIMIT_FSIZE (infinite) 8589934591
RLIMIT_LOCKS (infinite) 8589934591
RLIMIT_MEMLOCK 4295032832
RLIMIT_NOFILE 4294968320
RLIMIT_NPROC 4294968320
RLIMIT_RSS (infinite) 8589934591
RLIMIT_STACK 4303355904 8589934591 在代码中,由于资源是用 long long 类型表示的,所以在 printf 出来时,要使用 %lld 。 |
|