第十一章 进程和信号 进程和信号构成了linux操作系统环境的基础部分。它们控制着linux和所有其他类UNIX计算机系统执行的几乎所有活动。不管是对于系统程序员、应用程序员还是系统管理员,理解linux和UNIX系统的进程管理都是很有好处的。
11.1 什么是进程 UNIX标准把进程定义为:“
一个其中运行着一个或者多个线程的地址空间和这些线程所需要的系统资源。”目前,可以把进程看作正在运行的程序。
像linux这样的多任务操作系统可以同时运行多个程序。每个运行着的程序实例就构成了一个进程。
作为多用户系统,linux允许许多用户同时访问系统,每个用户可以同时运行许多个程序,甚至同时运行同一个程序的多个实例。系统本身也运行着一些管理系统资源和控制用户访问的程序。
正在运行的程序或者进程由程序代码、数据、变量(占用着系统内存)、打开的文件(文件描述符)和环境组成。一般来说,
linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份副本。
11.2 进程的结构 现在看看操作系统是如何管理多个进程的,如果有两个用户neil和rick,他们同时运行grep程序在不同的文件中查找不同的字符串,分别使用grep kirk trexk.txt和grep troi nextgen.doc命令
如果在搜索结束之前运行ps命令,则该命令输出类似下面的内容:
ps -ef
UID PID PPID TTY CMD
rick 101 96 tty2 grep troi nextgen.doc
neil 102 92 tty4 grep kirk trek.txt
每个进程都会分配一个唯一的数字编号,称之为进程标识符或PID。它通常是一个取值范围从2到32768的正整数。当进程被启动时,系统将按顺序选择下一个未被使用的数字作为它的PID,当数字已经回绕一圈时,新的PID重新从2开始。
数字1一般是为特殊进程init保留的,init进程负责管理其他进程。
将要被grep命令执行的程序代码被保存在一个磁盘文件中。正常情况下,
linux进程不能对用来存放程序代码的内存区域进行写操作,即程序代码是以只读方式加载到内存中的。虽然不能对这个区域进行写操作,但它可以被多个进程安全地共享。
系统函数库也可以被共享。例如不管有多少个正在运行的程序要调用printf函数,内存中只要有它的一份副本即可。这种做法与微软Windows操作系统中使用的动态链接库(DLL)机制类似,但是更加负责。
共享函数库的带来的另一个优点是,包含可执行程序grep的磁盘空间容量比较小,因为它不包含共享函数库代码,这对一个单独的程序来说,算不上优点,但对整个操作系统来说,把常用例程提取出来放入C语言的标准库中将节省大量的磁盘空间。
当然,并不是程序在运行时所需要的所有东西都可以被共享。例如,进程使用的变量就与其他进程所使用的截然不同。在本例中,传递给grep程序的搜索字符串以变量s的形式出现在各个进程的数据区中。它们之间是分离的,通常不能被其他进程读取。这两个grep命令所使用的文件也各不相同,进程通过各自的文件描述符来访问文件。
除此之外,进程有自己的栈空间,用于保存函数中的局部变量和控制函数的调用与返回。进程还有自己的环境空间,包含专门为这个进程建立的环境变量。进程还必须维护自己的程序计数器,这个计数器用来记录它执行到的位置,即在执行线程中的位置。在使用线程时,进程可以有不止一个执行线程。
在许多linux系统上,在目录/proc中有一组特殊的文件,这些文件的特殊之处在于它们允许"窥视"正在运行的进程的内部情况,就好像这些进程是目录中的文件一样。
最后,因为linux和UNIX一样,有一个虚拟内存系统,能够把程序代码和数据以内存页面的形式放到硬盘的一个区域中,所以linux可以管理的进程比物理内存所能容纳的要多得多。
11.2.1 进程表 linux
进程表就像一个数据结构,它把当前加载在内存中的所有进程的有关信息保存在一个表中,其中包括进程的PID、进程状态、命令字符串和其他一些ps命令输出的各类信息。操作系统通过进程的PID对它们进行管理,这些PID是进程表的索引。进程表的长度是有限制的,所以系统能够支持的同时运行的进程数也是有限制的。
11.2.2 查看进程
ps命令可以显示正在运行的进程、其他用户正在运行的进程或者目前在系统上运行的所有进程。例如之前的ps -ef中,
TTY一列显示了进程是从哪一个终端启动的,TIME一列是进程目前为止所占用的CPU时间,CMD一列显示启动进程所需要的命令。
neil 655 428 0 18:24 tty4 00:00:00 -bash
用户的初始登录是在第4个虚拟终端完成的,该终端是这台机器的一个主控台,运行的shell程序是linux系统的默认shell:bash。
root 717 716 13 18:28 pts/0 00:00:01 Emacs
这个进程代表这X视窗系统中一个运行着Emacs编辑器的窗口,它是由窗口管理器响应的一个创建新窗口的请求而启动的。系统还分配给shell一个新的伪终端pts/0,shell可以通过该终端进行读写操作。
默认情况下,ps程序只显示与终端、主控台、串行口或伪终端保持连接的进程的信息。其他进程在运行时不需要通过终端与用户进行通信,它们通常都是一些系统进程,linux用它们来管理共享的资源。可以用ps命令的-a选项来查看所有的进程,用-f选项显示进程完整信息。
11.2.3 系统进程 ps命令输出中的
STAT一列用来表明进程的当前状态。常用的STAT代码如下:
STAT代码 说明
S 睡眠。通常是等待某个事件的发生,如一个信号或有输入可用
R 运行。严格来说是"可运行",即在运行队列中,处于正在执行或即将运行状态
D 不可中断的睡眠(等待)。通常是在等待输入或输出完成
T 停止。通常是被shell作业控制所停止,或进程正处于调试器的控制之下
Z 死(Defunct)进程或者僵尸(Zombie)进程
N 低优先级任务,nice
W 分页
s 进程是会话期首进程
+ 进程属于前台进程组
l 进程是多线程的
$ ps ax
PIS TTY STAT TIME COMMAND
1 ? Ss 0:03 init [5]
9619 tty2 Ss+ 0:00 /sbin/mingetty tty2
一般而言,
每个进程都是由另一个称为父进程的进程启动,被父进程启动的进程叫做子进程。
linux系统启动时,它将运行一个名为init的进程,该进程是系统运行的第一个进程,它的进程号是1.可以把init进程看作为操作系统的进程管理器,它是其他所有进程的祖先进程。其他进程要么是由init进程启动的,要么是被init进程启动的其他进程启动的。
用户登录的过程就是一个这样的例子。init进程为每个用户用来登录的串行终端或拨号调制解调器启动一次getty程序。对应的ps命令输出入9619进程,getty进程等待来自终端的操作,向用户显示熟悉的登录提示符,然后把控制权交给登录程序,登录程序设置用户环境,最后启动一个shell。用户退出系统时,init进程将再次启动另一个getty进程。
启动新进程并等待它们结束的能力是整个系统的基础。
11.2.4 进程调度 ps命令的输出结果中还有一条对应ps命令本身的记录:
21475 pts/2 R+ 0:00 ps ax
这行表明进程21475处于运行状态(R),正在执行的命令式ps ax。也就是说,这个进程出现在自己的输出结果中了。这个状态指示符只表示程序已准备好运行,并不意味着它正在运行。在一条单处理器计算机上,同一时间只能有一个进程可以运行,其他进程处于等待运行状态。每个进程轮到的运行时间(时间片)是相当短暂的,这就给人一种多个程序在同时运行的假象。状态R+只表示这个程序是一个前台任务,它不是在等待其他进程结束或等待输入输出操作完成。这就是为什么可能会在ps命令的输出结果中看到两个这样的进程的原因(另一个常见的标记为正在运行的进程是X显示服务器)
linux内核用进程调度器来决定下一个时间片应该分配给哪个进程。它的判断依据是进程的优先级。优先级高的进程运行得更为频繁,而其他进程,如低优先级的后台任务运行就不是非常频繁。在linux中,进程的运行时间不可能超过分配给它们的时间片,它们采用的是抢占式多任务处理,所以进程的挂起和继续运行无需彼此之间的协作。
在一个如linux这样的多任务系统中,多个程序可能会竞争使用同一个资源。在这种情况下,
执行短期的突发性工作并暂停运行来等待输入的程序,要比持续占用处理器来进行计算或不断轮询系统来查看是否有新的输入到达的程序要更好。称表现良好的程序为nice程序,而且在某种意义上,这个nice是可以被计算出来的。操作系统根据进程的nice值来决定它的优先级,一个进程的nice值默认为0并将根据这个程序的表现而不断变化。长期不间断运行的程序的优先级一般会比较低,而暂定来等待输入的程序会得到奖励。这样可以帮助与用户进行交互的程序保持及时的响应性。在程序等待用户的输入时,系统会增加它的优先级。这样,当它准备继续运行时,它就会有比较高的优先级而能优先执行。可以用nice命令来设置进程的nice值,使用renice命令来调整它的值。nice命令式将进程的nice值增加10,从而降低该进程的优先级。可以用ps命令的-l或者-f选项来查看正在运行到额进程的nice值.(NI栏即是) 比如对进程号1362的oclock程序进行操作,使用下面的命令来启动它: $ nice oclock & 它将被分配到一个+10的nice值。如果用下面额命令来调整这个值: $ renice 10 1362 1362: old priority 0, new priority 10 这个时钟程序运行得就会不那么频繁了,可以用ps命令查看修改过的nice值。