首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

8.4  进程

进程是一条命令在Linux上的执行。用户登录时启动的shell,也是一条命令,或者进程。当用户在命令行中输入一个Linux工具名时,就启动了一个进程。当用户运行一个shell脚本的时候,系统创建另一个shell进程,并为脚本中的每行命令创建另外的进程。根据用户调用脚本方式的不同,脚本既可以由当前shell运行,也可由当前shell的一个子shell运行。后一种方式更加普遍。如果用户输入一条shell内置命令如cd,此时系统并不会创建进程。

8.4.1  进程结构

fork系统调用  进程结构类似于文件结构,它也是一个层次式机构,有父进程、子进程,甚至根进程。父进程可以创建子进程,子进程又可以创建其他进程。术语fork,就像道路中的岔道口一样,将一个进程变成两个进程。最初,除了一个被标识为父进程,另一个被标识为子进程之外,这两个“岔道口”是一样的。这里还可以使用术语衍生(spawn),这两个词可以互换。创建一个新的进程的操作系统例程(或者系统调用)叫做fork。

当系统启动时,Linux开始执行,它首先启动init进程。这个进程称为自发进程,其PID编号为1。这个进程在进程结构中的地位与文件结构中根目录的位置相同:它是系统进程和所有用户进程的祖先。当系统处于多用户模式时,init运行getty或者mingetty进程,这些进程将在终端和虚拟控制台上显示“login:”提示符。当某个用户响应该提示符并输入RETURN时,getty将控制权转交给名为login的实用程序,该实用程序检查用户名和密码组合。在用户登录之后,login进程将成为该用户的shell进程。

8.4.2  进程标识

PID编号  在每个进程开始的时候,Linux为其分配一个唯一的PID(process identification,进程标识)编号。在进程存在期间,它将一直持有这个PID编号。在一次会话期间,总有同一个进程在执行登录shell。当用户创建一个新的进程(比如,使用编辑器),新(子)进程的PID编号会不同于它的父进程。当用户返回到登录shell时,还是由同一个进程执行,并且它的PID编号与用户登录时的编号相同。

下面的示例展示了运行shell的那个进程创建了运行ps的进程,前者是后者的父进程。当带-f选项调用ps时,ps显示每个进程信息的完整列表。ps显示结果中,CMD列为bash的那一行表示运行shell的进程。PID列标示PID编号。PPID列标示该进程的父进程的PID编号。从PID列和PPID列可以看出,运行shell的进程(PID为21341)是运行sleep的进程(PID为22789)的父进程。sleep的父进程PID编号与shell的PID编号相同。

$ sleep 10 &

[1] 22789

$ ps -f

UID        PID PPID    C STIME TTY           TIME CMD

alex     21341 21340  0 10:42 pts/16   00:00:00 bash

alex     22789 21341  0 17:30 pts/16   00:00:00 sleep 10

alex     22790 21341  0 17:30 pts/16   00:00:00 ps -f

参见第Ⅴ部分第14.59节,可得到更多关于ps命令的信息以及带-f选项时显示的各列信息。第2对sleep和ps -f命令表明,该shell仍然由同样的进程运行,但是它创建了另一个进程来运行sleep:

$ sleep 10 &

[1] 22791

$ ps -f

UID         PID PPID    C STIME TTY           TIME CMD

alex     21341 21340   0 10:42 pts/16   00:00:00 bash

alex     22791 21341   0 17:31 pts/16   00:00:00 sleep 10

alex     22792 21341   0 17:31 pts/16   00:00:00 ps -f

还可以使用pstree(或者ps --forest,带或者不带选项-e)来查看进程的父子进程关系。下面的示例中显示了带-p选项的pstree命令运行的结果,该选项使其显示了PID编号:

$ pstree -p

init(l)-+-acpid(1395)

|-atd(1758)

|-crond(1702)

...

|-kdeinit(2223)-+-firefox(89l4)—--run-mozilla.sh(8920)—firefox-bin

(8925)

|               |-gaim(2306)

|               |-gqview(14062)

|               |-kdeinit(2228)

|               |-kdeinit(2294)

|              |-kdeinit(2314)-+-bash(2329)---ssh(2561)

|               |                 |-bash(2339)

|               |                 '-bash(15821)---bash(16778)

|               |-kdeinit(16448)

|               |-kdeinit(20888)

|               |-oc1ock(2317)

|               '-pam-panel-icon (2305 )---pam_timestamp_c(2307)

...

|-1og-in(1823)---bash(20986)-+-pstree(21028)

|                                 '-s1eep(21026)

...

这里的输出省略了一部分内容。以-kdeinit开头的行显示了图形用户运行了很多进程,包括firefox、gaim和oclock。以-login开头的行则表明文本用户在后台运行sleep,同时还在前台运行pstree。参见第11.3.3节中的“$$:PID编号”部分,它描述了如何让shell报告PID编号。

8.4.3  执行命令

fork和sleep  当用户向shell中输入一行命令时,shell同时创建(衍生)一个子进程来执行这条命令。当子进程执行该命令期间,父进程转入睡眠状态。当某个进程睡眠时,它并不占用任何计算机时间,但是它还保持非活跃状态,等待被唤醒。当子进程的命令执行完毕之后,它将通过其退出状态通知其父进程自己执行成功或者失败,然后消逝。父进程(正在运行shell的进程)被唤醒,然后提示用户输入另外一个命令。

后台进程  当通过在命令结尾处加上“逻辑与”符号(&)将进程置于后台运行时,shell创建一个子进程,但是shell并不进入睡眠状态,也不用等待子进程去运行完毕。执行shell的父进程报告作业编号和子进程的PID编号,并提示输入另一个命令。子进程在后台执行,独立于它的父进程。

内置命令  尽管大多数时候,在用户输入命令后,shell会创建一个新的进程来运行该命令。但是有些命令是shell的内置命令。shell运行内置命令时,并不需要创建新的进程。参见第5.5节以获取更多信息。

变量  在给定进程内,比如用户的登录shell或者子shell,用户可以声明、初始化、读取和改变变量。然而在默认情况下,变量只适用于进程本地范围。当进程创建一个子进程时,父进程并不会将变量的值传递给它的子进程。使用bash下的export内置命令或者tcsh下的setenv内置命令可使这些变量也可以被子进程访问(此时为全局变量)。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论