全部博文(842)
分类: 系统运维
2012-05-14 15:15:25
工作控制是在1980年前后加入到BSD的一个特性。这个特性允许我们在单个终端开启多个工作(进程组),并控制哪些工作可以访问终端和哪些工作在后台运行。工作控制需要三种形式的支持:
1、一个支持工作控制的外壳;
2、内核里的终端驱动必须支持工作控制;
3、内核必须支持特定的工作控制信号。
SVR3提供了另一种形式的工作控制,被称为外壳层。BSD形式的工作控制,被POSIX.1选择,也是我们在这讨论的。在这个标准的更早的版本里,工作控制支持是可选的,但是现在POSIX.1要求平台来支持它。
从我们的角度,从一个外壳使用工作控制,我们可以在前台或后台开始一个工作。一个工作是简单的一个进程集合,经常是一个进程的管道。例如:vi main.c打开了一个由一个前台进程组成的工作。命令pr *.c | lpr &
make all &
在后台开启了两个工作。后台工作调用的所有进程都在后台里。
正 如我们说过的,为了使用工作控制提供的特性,我们需要使用支持工作控制的一个外壳。在早期系统,说出哪些外壳支持而哪些外壳不支持工作控制很简单。C外壳 支持工作控制、在Bourne外壳不支持、而在Korn外壳里是一个可选项,取决于主机是否支持工作控制。但是C外壳被移植到不支持工作控制的系统(例 如,系统V的早期版本),而SVR4 Bourne外壳,当使用名字jsh而不是sh时,会支持工作控制。Korn外壳继续支持工作控制,如果主机支持的话。Bourne-again外壳也支 持工作控制。我们将只泛泛地说一个支持工作控制,对应不支持工作控制的那些,当各种外壳的区别无关紧要时。
当我们开始一个后台工作进,外壳给它分配一个工作标识符并打印一个或多个进程ID。下面的脚本展示Korn外壳如何处理这个:
$make all > Make.out &
[1] 1475
$ pr *.c | lpr &
[2] 1490
$ (只输入回车)
[2] + Done
[1] + Done
make 的工作号为1而开始进程ID为1475.下一个管道的工作号为2而第一个进程的进程ID为1490。当工作完成时,而我们按下回车,外壳告诉我们工作完成 了。我们必须按回车的原因是让外壳打印它的提示。外壳不在任何随机时间打印后台工作的改变状态--只是在它打印它的提示前,来让我们输出一个新的命令行。 如果外壳不这样做,它可能在我们输入一个输入行时输出。
和终端驱动的交互由于一个特殊终端字符影响了前台工作而发生:挂起键(典型的Control-Z)。输出这个字符导致终端驱动发送SIGTSTP信号给前台进程组的所有进程。任何后台进程进程组不被影响。终端驱动查找三个特殊的字符,它们产生对前台进程组的信号:
1、中断字符(一般是DELETE或Control-C)产生SIGINT;
2、退出字符(一般是Control-backslash)产生SIGQUIE;
3、挂起字符(一般是Control-Z)产生SIGTSTP。
在18章,我们将看到我们怎样改变这三个字符成为我们选择的任意字符,以及我们如何禁止终端驱动处理这些特殊字符。
另 一个必须由终端驱动处理的工作控制可以发生。既然我们可以有一个前台工作和一个或多个后台工作,这些中的哪台接受我们在终端输入的字符呢?只有前台工作接 受终端输入。后台工作尝试从终端读不是一个错误,但是终端驱动察觉到它并向后台工作发送一个特殊的信号:SIGTTIN。这个信号一般停止后台工作。通过 使用外壳,我们收到这个通知并可以把这个工作带入前台,以便它可以从终端读取。证明如下:
$ cat > temp.foo &
[1] 2333
$ (回车)
[1]+ 已停止 cat > temp.foo
$ fg %1
cat > temp.foo
hello, world
$ cat temp.foo
hello, world
外
壳在后台启动cat进程,但是当cat尝试读取它的标准输入(控制终端),终端驱动知道它是一个后台工作,发送SIGTTIN信号给这个后台工作。外壳察
觉它子进程状态的改变(回想8.6节wait和waitpid函数的讨论)并告诉我们工作已经被停止了。我们然后用外壳的fg命令把停止的工作移到前台
来。(参考shell的手册而来得到工作控制命令的所有细节,比如fg和bg,以及标识不同工作的各种方法。)这样做导致外壳把工作移到前台进程组
(tcsetpgrp)并发送继续信号(SIGCONT)给这个进程组。既然它现在在前台进程组时,这个工作可以从控制终端读取。
如果一个后台工作输出到控制终端会发生什么呢?这是一个我们可以允许或禁止的可选项。通常,我们使用stty命令来改变这个选项。(我们将在18章看到我们如何可以从一个程序里改变这个选项。)下面展示这如何工作:
$ cat temp.foo &
[1] 2385
$ hello, world
(输入回车)
[1]+ 完成 cat temp.foo
$ stty tostop
$ cat temp.foo &
[1] 2387
$ (输入回车)
[1]+ 已停止 cat temp.foo
$ fg 1
cat temp.foo
hello, world
当我们禁止前台工作向控制终端写时,cat会在其尝试向标准输出写时阻塞,因为终端驱动标识了这个写是从一个后台进程来的,并向这个工作发送SIGTTOU信号。正如前面的例子,当我们使用外壳的fg命令把工作带入到前台时,工作完成。
下面总结了我们已经描述过的工作控制的一些特性:
1、init或inetd启动一个新的会话。这个会话包含后面的内容;
2、由init或inetd创建的getty或telnetd进程,在调用setsid后,建立控制终端,并通过exec执行login;
3、login通过exec执行登录外壳;
4、登录外壳调用setpgid创建前台进程组和后台进程组,并向终端驱动调用tcsetpgrp来为控制终端设置进程组;
5、终端上的用户与终端驱动交互,终端输入和终端产生的信号(SIGINT、SIGQUIT和SIGTSTP)被发送给前台进程;前台进程向终端驱动发送终端输出;
6、后台进程读取终端输入时,终端驱动向它发送SIGTTIN信号;后台进程向终端输出时,终端驱动可能向它发送SIGTTOU信号;
7、前台进程和后台进程的状态改变时,登录外壳会收到通知。
工 作控制是必需的还是可取的?工作控制最初在窗口终端被广泛使用前被设计和实现。一些人指出一个良好设计的窗口系统移除了工作控制的需求。一些人则抱怨工作 控制的实现--需要内核、终端驱动、外壳和一些应用程序的支持--是一个hack。一些人在一个窗口系统里使用工作控制,要求两者都需要。不管你的意见如 何,工作控制是POSIX.1的一个必需的特性。