作业控制指的是控制正在运行的进程的行为。比如,用户可以挂起一个进程,等一会儿再继续执行该进程。shell将记录所有启动的进程情况,在每个进程过程中,用户可以任意地挂起进程或重新启动进程。作业控制是许多shell(包括bash和tcsh)的一个特性,使用户能在多个独立作业间进行切换。
一般而言,进程与作业控制相关联时,才被称为作业。
在大多数情况下,用户在同一时间只运行一个作业,即它们最后向shell键入的命令。但是使用作业控制,用户可以同时运行多个作业,并在需要时在这些作业间进行切换。这会有什么用途呢?例如,当用户编辑一个文本文件,并需要中止编辑做其他事情时,利用作业控制,用户可以让编辑器暂时挂起,返回shell提示符开始做其他的事情。其他事情做完以后,用户可以重新启动挂起的编辑器,返回到刚才中止的地方,就象用户从来没有离开编辑器一样。这只是一个例子,作业控制还有许多其他实际的用途。
由Shell进程fork
出的子进程本来具有和Shell相同的Session、进程组和控制终端,但是Shell调用setpgid
函数将作业中的某个子进程指定为一个新进程组的Leader,然后调用setpgid
将该作业中的其它子进程也转移到这个进程组中。如果这个进程组需要在前台运行,就调用tcsetpgrp
函数将它设置为前台进程组,由于一个Session只能有一个前台进程组,所以Shell所在的进程组就自动变成后台进程组。
在上面的例子中,proc3
、proc4
、proc5
被Shell放到同一个前台进程组,其中有一个进程是该进程组的Leader,Shell调用wait
等待它们运行结束。一旦它们全部运行结束,Shell就调用tcsetpgrp
函数将自己提到前台继续接受命令。但是注意,如果proc3
、proc4
、proc5
中的某个进程又fork
出子进程,子进程也属于同一进程组,但是Shell并不知道子进程的存在,也不会调用wait
等待它结束。换句话说,proc3 | proc4 | proc5
是Shell的作业,而这个子进程不是,这是作业和进程组在概念上的区别。一旦作业运行结束,Shell就把自己提到前台,如果原来的前台进程组还存在(如果这个子进程还没终止),则它自动变成后台进程组