Ctrl-C如何终止subprocess?

我想了解如何CTRL + C终止一个孩子,但不是一个父进程。 我在一些像bash这样的脚本shell中看到了这种行为,您可以在其中启动一些长时间运行的进程,然后通过inputCTRLC并将控制返回到shell来终止它。

你能解释它是如何工作的,特别是为什么不是父(shell)进程终止?

shell是否必须对CTRL + C事件做一些特殊的处理,如果是,它究竟做了什么?

内核处理默认信号。 旧的Unix系统有15个信号; 现在他们有更多。 你可以检查</usr/include/signal.h> (或kill -l)。 CTRL + C是名称为SIGINT

内核也定义了处理每个信号的默认操作,通常它会终止接收信号的进程。

所有的信号(但是SIGKILL )都可以通过程序来处理。

这就是shell所做的事情:

  • 当shell以交互模式运行时,它有一个特殊的信号处理模式。
  • 当你运行一个程序时,例如find ,shell:
    • fork本身
    • 并为孩子设置默认的信号处理
    • 用给定的命令replace孩子(例如用find)
    • 当你按CTRL + C ,父shell处理这个信号,但是孩子会收到它 – 默认行动 – 终止。 (孩子也可以执行信号处理)

你也可以在你的shell脚本中trap信号。

你也可以为你的交互式shell设置信号处理,试着在你的顶部input~/.profile 。 (确保你已经login,并用另一个terminal进行testing – 你可以locking自己)

 trap 'echo "Dont do this"' 2 

现在,每次在你的shell中按CTRL + C ,它都会打印一条消息。 不要忘记删除线!

如果感兴趣的话,可以在这里查看源代码中的plain old /bin/sh信号处理。

在上面的评论(现在删除)有一些误导,所以如果有人在这里感兴趣是一个非常不错的链接 – 信号处理如何工作 。

首先,请阅读POSIXterminal界面上的Wikipedia文章 。

SIGINT信号由terminal线路规则生成,并广播给terminal的前台进程组中的所有进程。 您的shell已经为您运行的命令(或命令pipe道)创build了一个新的进程组,并告诉terminal该进程组是其terminal的前台进程组。 每个并发命令stream水线都有自己的进程组, 前台命令stream水线就是shell已经编入terminal的进程组作为terminal的前台进程组。 在前台和后台之间切换“作业”(有些细节放在一边)是关于shell告诉terminal哪个进程组现在是前台的问题。

shell进程本身还在另一个进程组中,并且当其中一个进程组处于前台时不会收到信号。 就这么简单。

terminal将INT(中断)信号发送到当前连接到terminal的进程。 程序然后收到它,并可以select忽略它,或退出。

没有进程必然被强制closures(尽pipe默认情况下,如果你不处理sigint,我相信行为是调用abort() ,但我需要看看)。

当然,运行的进程与启动它的shell是隔离的。

如果你想要使用父shell,用exec启动你的程序:

 exec ./myprogram 

这样,父shell被replace为subprocess

CTRL + C是kill命令的映射。 当你按下它们时,kill会发送一个SIGINT信号,这会中断进程。

杀死: http : //en.wikipedia.org/wiki/Kill_(command)

SIGINT: http : //en.wikipedia.org/wiki/SIGINT_(POSIX)