对话 UNIX,第 8 部分: UNIX 进程( 三 )


图 3. 进程 A 生成自身的克隆体
起初 , 进程 Z 是从进程 A 停止的地方开始执行的 。也就是说 , 此后进程 Z 从指令 14 (Instruction 14) 处开始执行 。进程 A 会在同一指令位置继续执行 。
一般来说 , 指令 14 处的编程逻辑将测试当前的进程是子进程还是父进程 , 也就是说 , 进程 Z 和进程 A 中的指令 14 分别判定这两个进程是否为其他进程的后代或祖先 。为了以示区别 , fork() 系统调用在子进程中返回 0 , 但返回给父进程的却是进程 Z 的进程 ID 。
在上次测试之后 , 进程 A 和进程 Z 会出现差异 , 每个进程会采用单独的代码路径 , 就像路上出现岔道 , 每一个都会走上不同的分枝 。生成一个新进程的流程更多地被称为分叉 , 这就像两位旅行者走到了路上的岔道 。因此 , 系统调用被命名为 fork() 。
在分叉之后 , 进程 A 可能会继续运行同一个应用程序 。而进程 Z 则可能立即发生变化 , 转到另一个应用程序 。后一种操作会改变程序通过进程运行的内容 , 它被称为执行 , 但您可以把它看成是一次再生过程:虽然进程 ID 不变 , 但进程内部的指令会被新程序的指令完全取代 。图 4 显示的是稍后进程 Z 的状态 。
图 4. 进程 Z 现在独立于它的祖先 , 即进程 A
分叉
您可以在自己的命令行 , 很方便地体验分叉操作 。首先 , 打开一个新的 xterm 。(您现在可能会认识到 , xterm 就是它本身的进程 , 在 xterm 中 , shell 是由 xterm 产生的一个独立进程) 。接下来 , 输入:ps -o pid,ppid,uname,command,state,stime,time
您应该会看到类似这样的内容: PID PPID USER COMMAND S STIME TIME
16351 16350 mstreic -bashS 11:23 00:00:00
16364 16351 mstreic ps -o pid,ppid,u R 11:24 00:00:00从该列表的 PPID 字段中 , 我们知道 ps 命令是 bash shell 的子进程 。(-bash 中的连字符说明 shell 实例是一个登录 shell 。)为了运行 ps , bash 会分叉 , 创建一个新进程;新进程通过使用执行 , 使其本身得以重生 , 转化为 ps 的一个新的实例 。
这里是另一个可供尝试的实验 。键入:sleep 10 & sleep 10 & sleep 10 & ps -o pid,ppid,uname,command,state,stime,time
您应该会看到类似这样的内容:$ sleep 10 & sleep 10 & sleep 10 & ps -o pid,ppid,uname,command,state,stime,time
 PID PPID USER COMMAND S STIME TIME
16351 16350 mstreic -bashS 11:23 00:00:00
16843 16351 mstreic sleep 10 S 11:42 00:00:00
16844 16351 mstreic sleep 10 S 11:42 00:00:00
16845 16351 mstreic sleep 10 S 11:42 00:00:00
16846 16351 mstreic ps -o pid,ppid,u R 11:42 00:00:00命令行生成四个新进程 。在每个 sleep 命令后键入 & , 在后台运行每一个命令 , 或与 Shell 并行 。ps 是生成的另一个进程 , 但它是在前台运行的 , 可以防止 shell 在该进程终止之前运行其他命令 。而且 , 如 PPID 的值所示 , 所有四个进程都是 Shell 的后代 。三个 sleep 命令都被标为 S , 因为没有哪个进程会在它们睡眠时使用资源 。
为了方便起见 , shell 会持续跟踪它生成的所有后台进程 。键入 jobs , 可以看到一个列表:
$ sleep 10 & sleep 10 & sleep 10 &
[1] 16843
[2] 16844
[3] 16845
$ jobs
[1]Running sleep 10 &
[2]Running sleep 10 &
[3]Running sleep 10 &此处 , 为了方便起见 , 三个工作分别用标签标为 1 , 2 和 3 。数字 16843、16844 和 16845 分别是每个进程的进程 ID 。因此 , 后台任务 1 即为进程 ID 16843 。
您可以利用这些标签 , 从命令行操作您的后台工作 。例如 , 如要终止某个命令 , 键入 kill %N , 其中 N 是该命令的标签 。如要将某个命令由后台移到前台 , 请键入 fg %N :

推荐阅读