# Ctrl-C
Ctrl-C
我们再熟悉不过了,可如果一开始,我们有 Ctrl-C
这样一个具体的需求,操作系统应该怎样设计 / 实现?
UNIX
信号job control
怎样在shell
里管理多个进程
为什么 Ctrl-C
能退出程序?
1. Ctrl-C
并不能杀掉所有的程序,比如没法用 Ctrl-C
来退出 vim
2. 两个进程同时使用了 read(STDIN_FILENO,buf,size);
,按下 Ctrl-C
,谁收到了?
Ctrl-C
的背后涉及若干操作系统中的对象
按下 Ctrl-C
的终端
tty(1)
echo hello > $(tty)
我们甚至可以向其它tty
打印
事实上,它俩都不是最先收到 Ctrl-C
的,终端最先收到 Ctrl-C
,向前台的进程组 (process group)
发送了 SIGINT
信号,这是一种进程间通信的机制,和 (管道) pipe
和 (共享内存) mmap
一样,只不过信号是异步的,而管道和共享内存是同步的,在按下 Ctrl-C
时,同时给进程发送了信号 signal
,进程就会跳转到处理器预设的 signal
处理程序,等于说在软件上模拟硬件上的中断机制,使得可以在进程间做异步通信。
# signal 函数
//signal 函数原型 | |
#include <signal.h> | |
typedef void (*sighandler_t)(int); | |
sighandler_t signal(int sinum,sighandler_t handler); |
对于 sighandler_t signal(int signum, sighandler_t handler)
函数来说, signum
显然是信号的编号, handler
是中断函数的指针。 typedef void (*sighandler_t)(int)
中断函数的原型中,有一个参数是 int
类型,显然也是信号产生的类型,方便使用一个函数来处理多个信号。
signal()
会按照参数 signum
指定的编号来设置该信号的处理函数,当指定的信号到达时就会跳转到参数 handler
指定的函数执行,如果参数 handler
不是指针,则必须是下列两个常数之一:
SIG_IGN
忽略参数signum
指定的信号SIG_DFL
将参数signum
指定的信号重设为预设的信号处理方式
返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)
当使用 vim
编辑时,之所以 Ctrl-C
无效,因为它的进程不响应这个机制;在手册里,有这样说, signal()
可以设置一个编号为 signum
信号的 handler
,可以有 SIG_IGN
(忽略这个信号)、 SIG_DFL
(默认的信号处理程序),对于 Ctrl-C
来说, SIG_DFL
的处理就是退出程序;而 vim
设定了一个自定义的 signal handler
# job control
何为 PID
?进程标识符,为每个进程分配唯一标号,进程创建时分配 PID
, Shell
支持前台进程组和后台进程组,进程组指的是已从 shell
命令行启动的命令;通常,前台进程组可以控制终端;一个程序也可以附上 &
被后台运行,比如 testrun
是一个程序, testrun &[2] 4365
成为一个后台进程组;如果后台启动了多个进程组, shell
将按照这些进程组启动的顺序进行编号,比如
$ testrun &[2] 4365 | |
$ backup &[3] 4374 | |
$ account &[4] 4377 |
当后台进程组完成了会报 [1] + done testrun
,jobs 命令将会列出所有的后台进程组, jobs -l
选项还可以列出 PID
,比如
[2] Running testrun & | |
[3]- Running backup & | |
[4]+ Running account & |
另外, fg(foreground)
命令可以在前台恢复执行被挂起的进程,默认情况下, fg
和下面的 bg
针对于最近的进程,如果有编号,比如 fg %2
,表示使第 2 个任务在前台运行;或者可以使用 fg %testrun
命令, %+
针对于最近的后台进程组,而 %-
针对于次新的后台进程组。 Ctrl-Z
可以用来挂起一个进程放入后台, bg
命令可以在后台恢复执行被挂起的进程,而此时将无法再使用 Ctrl-Z
再次挂起该进程。比如,正在使用 vi
编辑一个文件,需要执行 shell
命令查询一些需要的信息,可以使用 Ctrl-Z
挂起 vi
,等执行完 shell
命令之后再使用 fg
恢复 vi
继续编辑你的文件。