进程详细剖析(三)
5.14 进程资源
进程为了能够执行它索要执行的任何任务,可能需要将数据写入文件,将数据发送到打印机、或者在屏幕上显示数据。进程可能需要来自用户的输入,经由键盘或从文件中输入。进程可以使用其他进程作为资源,例如子程序。子程序、文件、
信号量、互斥量、键盘、显示器等都是进程可以利用的资源的实例。资源是被进程在任何指定时间作为数据源、作为处理或计算的工具、作为显示数据或信息的工具来使用的任何事物。进程若想访问资源,必须首先对操作系统发出请求。如果资源可用,则操作系统运行进程使用该资源。进程使用资源,然后释放它,这样资源对其他进程就可用了。如果资源不可用,则请求被拒绝,进程必须等待。当资源变为可用时,进程将被唤醒。这是资源分配的基本形式。下图显示了资源分配图。资源分配图显示出哪些进程持有资源以及哪些进程正在请求资源。下图中,进程B对资源2进行请求,该资源被进程C持有。进程C发出对资源3的请求,该资源被进程D持有。
当允许对一个资源的多个请求时,该资源是可共享的,如上图所示。进程A和进程D共享资源1。资源可能允许很多进程并发访问,或者允许另一个进程访问之前,只允许一个进程访问有限的时间。这种类型的共享资源的一个实例就是处理器。一个进程会被指派到
处理器上允许很短的时间间隔,然后另一个进程被指派给处理器。当任意时刻只能够有一个访问资源的请求被允许,而且必须发生在资源被另一个进程释放后,此时我们成这个资源时不可共享的,而且进程对资源进行的是排他访问。在多处理器环境中,了解一个共享资源是可以被同时访问还是每次只能被一个进程访问时非常重要的,能够避免一些并发带来的陷阱。
进程可能会更改一些资源,而有些资源不允许进程更改它们。共享的可更改资源或共享的不可更改资源的性质是由资源的类型决定的。
5.14.1 资源的类型
有3种基本的资源类型:
1)硬件
2)数据
3)软件
硬件资源时连接到计算机的物理设备。硬件资源的实例包括处理器、内存和所有的I/O设备,包括处理器、硬盘。磁带机、zip驱动器、显示器、键盘、声卡、网卡、显卡、调制解调器等。所有的这些设备都可以被多个进程共享。
有些硬件资源时抢占式的,运行不同进程访问。例如,处理器是抢占式的,从而可以运行不同的进程。RAM是另一个共享的可抢占资源的实例。当一个进程不被使用时,它所占有的一些物理页帧可能会被换出到二级存储,使得其他进程可以换入一些页帧来占据那些可用空间。一块内存在任意时刻只能够被一个进程的页帧所占据。非抢占式共享资源的一个实例时打印机。当打印机被共享时,每个进程发送给打印机的作业会被保存在队列中。每个作业打印完毕之后,另一个作业才能够开始。打印机不会被任何等待中的作业抢占,除非当前作业被取消。
数据资源包括:对象guan变量/文件和句柄等系统数据;信号量等全局定义变量;互斥量. 这些都是被进程共享和更改的资源。正规文件和可以打开的物理设备(如打印机)相关联的文件,限制了能够访问该文件的进程类型。可能会允许只读或只写的访问或读、写访问。对于有着父子进程打开的文件中推动文件指针,或关闭、修改、重写文件内容。共享内存和允许写入的文件要求同步对它们的访问。类似信号量或互斥量的共享数据可用于对这些共享数据资源的同步。
共享库时软件资源的实例。共享库我进程提供了服务或函数的公共集合。进程还可以共享应用程序、程序和实用工具。在这种情况下,只有一份程序代码的副本将放到内存中,然而有着多份数据副本,每个用户(进程)一份。不会改变的程序代码(也被称作可重入)可以被多个进程同时访问。
5.14.2 设置资源限制的POSIX函数
POSIX定义了限制进程使用特定资源能力的函数。操作系统对进程利用系统资源的能力设置了限制。这些资源限制影响如下方面:
1)进程栈的大小
2)创建的文件大小和内核文件的大小
3)CPU使用数量(时间片的大小)
4)内存使用数量
5)打开的文件描述符的数目
操作系统对进程的资源使用设置了硬限制。进程可以设置或改变其资源的软限制。它的值不应当超过由操作系统设置的硬限制。进程可以降低它的硬限制。这个值应当大于或者等于软限制。当进程降低其硬限制时,这个过程是不可逆的。只有少数有着特定特权的进程可以增加它们的硬限制。
调用形式
#include <sys/resource.h>
int setrlimit(int resource, const struct rlimit *rlp);
int getrlimit(int resource, struct rlimit *rlp);
int getrusage(int who, struct rusage *r_usage);
函数setrlimit()对特定资源的消耗设置限制。这个函数可以设置硬限制和软限制。参数resource表示资源类型。表5-7列出了resource的值以及简要的概述。指定资源的限制和硬限制由rlp参数表示。参数rlp指向rlimit结构体,其中包含两个类型为rlim_t的对象:
struct rlimit
{
rlim_t rlim_cur;
rlim_t rlim_max;
}
rlim_t是无符号整数类型。rlim_cur包含当前的软限制,rlim_max包含硬限制的最大值。可以对rlim_cur和rlim_max赋任意值,还可以将它们赋值为下列在头文件<sys/resource.h>中定义的符号常量。
1)RLIM_INFINITY: 代表无限
2)RLIM_SAVED_MAX: 代表无法表示保存的硬限制
3)RLIM_SAVED_CUR:代表无法表示保存的软限制
软限制或硬限制可以设置为RLIM_INFINITY,意味着资源时不受限制的。
函数getrlimit()返回在rlp对象中指定的资源的软限制和硬限制。函数getrlimit()和setrlimit()都是在成功时返回0,失败时返回-1.以下实例包含了进程为文件(以字节为单位)设置软限制的实例。
#include <sys/resource.h>
//...
struct rlimit R_limit;
struct rlimit R_limit_values;
//...
R_limit.rlim_cur = 2000;
R_limit.rlim_max = RLIM_SAVED_MAX;
setrlimit(RLIMIT_FSIZE, &R_limit);
getrlimit(RLIMIT_FSIZE, &R_limit_values);
cout << "file size soft limit: " << R_limit_values.rlim_cur << endl;
// ...
在上面实例中,文件规模的软限制被设置为2000字节,硬限制被设置为其最大值。传递给setrlimit()的参数为R_limit 和RLIMIT_FSIZE. 传递给getrlimit()函数的参数时FLIMIT_FSIZE 和 R_limit_values。软限制的值被发送给cout。
函数getrusage()返回关于调用进程使用资源的度量信息,还返回关于调用进程正在等待的终止的子进程的信息。参数who可以为以下值:
1)RUSAGE_SELF
2)RUSAGE_CHILDREN
如果who的值为RUSAGE_SELF,那么返回的信息是和调用进程相关的。如果who的值为RUSAGE_CHILDREN, 那么返回信息是和调用进程的子进程相关的。如果调用进程等不等待它的子进程,那么关于子进程的信息会被抛弃。信息在r_usage中返回,r_usage指向rusage结构体,该结构体中包含表5-8中列出并描述的信息。如果函数成功,则返回0,如果失败,则返回-1.