作业控制
作业控制是BSD在1980年前后增加的一个特性。
它允许在一个终端上启动多个作业(进程组),它支持控制哪一个作业可以访问终端,以及哪些作业可以在后台运行。
作业可以看做是shell管理的进程
作业控制的条件
主要有三点:
- 支持作业控制的shell
- 内核中的终端驱动程序必须支持作业控制
- 内核必须提供对某些作业控制信号的支持
理解作业控制
从shell使用作业控制功能角度讲,用户可以在前台或后台启动一个作业。
如以下命令:
$ vim main.c
就会在前台启动只有一个进程组成的作用。
$ pr *c | lpr &
$ make all &
在后台启动了两个作业,这两个作业调用的所有进程都在后台运行。
当启动一个后台作业时,shell赋予它一个作业标识,并打印一个或几个进程的ID。
$ make all > Make.out &
[1] 1475
$ pr *c | lpr &
[2] 1490
$ (键入回车)
[2] + Done pr *c | lpr &
[1] + Done make all > Make.out &
make的作业号是1,启动的进程ID是1475.下一个管道线是作业号2,其第一个进程的进程ID是1490。
当我们作业完成并且键入回车时,shell通知我们作业已完成并打印其提示符。
shell并不在任何随意时刻打印后台作业的状态改变,它只在打印其提示符让用户输入新的命令行之前才这样做。
改变作业控制
我们可以依靠挂起键Ctrl+Z
来影响前台作业。
键入此字符使终端驱动程序将信号SIGTSTP
送至前台进程组中的所有进程,后台作业则不受影响。
以下三个特殊字符可使终端驱动程序产生信号,并将其送至前台:
- 中断字符(
DELETE或Ctrl+C
)产生SIGINT
- 退出字符(
Ctrl+\
)产生SIGQUIT
- 挂起字符(
Ctrl+Z
)产生SIGTSTP
当我们有一个前台作业以及或若干个后台作业时,是哪一个接受我们在终端上键入的字符呢?
只有前台作业接收终端输入!
但是!后台作业试图读取终端也不是一个错误,终端驱动程序将会检测到这种情况,并且向后台作业试图读终端发送一个信号SIGTTIN
,该信号会暂停此后台作业。
后台作业如何读取终端输入
当然,用户可以用shell命令将此作业转为前台作业运行。
$ car > temp.foo & //在后台启动,但是从标准输入读
[1] 1681
$ (Enter)
[1] + Stopped(SIGTTIN) //cat > temp.foo &
$ fd %1 //1号作业成为前台作业
cat > temp.foo
hello world //输入hello world
^D //输入文件结束符
$ cat temp.foo
hello world
后台作业如何输出到终端
后台作业输出到终端是一个我们可以允许或禁止的选项,通常用stty
命令。
$ cat temp.foo &
[1] 1719
$ hello world
(Enter)
[1] + Done
$ stty tostop //禁止后台作业输出至控制终端
$ cat temp.foo &
[1] 1721
$ (Enter)
[1] + Stopped(SIGTTOU) cat temp.foo &
$ fg %1
cat temp.foo
hello world
参考文献
[1] UNIX环境高级编程(第二版)