![為什麼 Ctrl-C 不起作用?](https://rvso.com/image/50588/%E7%82%BA%E4%BB%80%E9%BA%BC%20Ctrl-C%20%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8%EF%BC%9F.png)
我只是敲了兩下Ctrlc我的外殼,試圖停止一個需要很長時間才能完成的進程。
^C
被重複了兩次,但這個過程一直在繼續。
為什麼Ctrlc不像平常那樣退出進程?
答案1
進程可以選擇:
- 忽略通常在按下時發送的 SIGINT 訊號Ctrl-C(就像在 shell 中一樣
trap '' INT
),或有自己的處理程序決定不終止(或無法及時終止)。 - 告訴終端設備導致 SIGINT 傳送到前台作業的字元是其他字元(例如
stty int '^K'
shell 中的 with ) - 告訴終端設備不要發送任何訊號(就像
stty -isig
在 shell 中一樣)。
或者,它們可以是不可中斷的,例如在無法中斷的系統呼叫過程中。
在 Linux(具有相對較新的核心)上,您可以判斷進程是否正在忽略和/或處理SIGINT 透過查看輸出
$ kill -l INT
2
$ grep Sig "/proc/$pid/status"
SigQ: 0/63858
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 0000000000000000
SIGINT為2。
您可以透過以下方式自動化該操作:
$ SIG=$(kill -l INT) perl -lane 'print $1 if $F[0] =~ /^Sig(...):/ &&
$F[1] & (1<<($ENV{SIG}-1))' < "/proc/$pid/status"
Ign
若要檢查目前intr
字元是什麼或是否isig
為給定終端啟用:
$ stty -a < /dev/pts/0
[...] intr = ^C [...] isig
(上面的intr
字元是^C
(通常由您的終端(模擬器)在按下CTRL-C並且輸入訊號未停用時發送的字元。
$ stty -a < /dev/pts/1
[...] intr = ^K [...] -isig
(intr
字元 是^K
且isig
已停用/dev/pts/1
)。
為了完整起見,進程還可以透過其他兩種方式來停止接收 SIGINT,儘管這不是您通常會看到的。
之上Ctrl+C,SIGINT 訊號被傳送到進程中的所有進程。終端機的前台進程組。通常是 shell 將進程放置在進程組中(映射到 shell工作)並告訴終端設備哪一個是前景一。
現在一個流程可以:
離開其進程組。如果它移動到另一個進程組(除當前進程組之外的任何進程組)前景一),那麼它將不再接收 SIGINT Ctrl-C(也不再接收其他鍵盤相關訊號,如 SIGTSTP、SIGQUIT)。然而,如果它嘗試從終端設備讀取(也可能根據終端設備設定寫入)(如後台進程所做的那樣),它可能會被掛起。
舉個例子:
perl -MPOSIX -e 'setpgid(0,getppid) or die "$!"; sleep 10'
不能被中斷Ctrl-C。上面
perl
將嘗試加入ID與其父進程ID相同的進程組。一般來說,不能保證存在具有該 ID 的進程組。但在這裡,如果該perl
命令在互動式 shell 的提示下單獨運行,則 ppid 將是 shell 的進程,而 shell 通常會在自己的進程組中啟動。如果該命令還不是進程組領導者(該前台進程組的領導者),那麼它啟動一個新的進程組將具有相同的效果。
例如,根據外殼,
$ ps -j >&2 | perl -MPOSIX -e 'setpgid(0,0) or die "$!"; sleep 10' PID PGID SID TTY TIME CMD 21435 21435 21435 pts/12 00:00:00 zsh 21441 21441 21435 pts/12 00:00:00 ps 21442 21441 21435 pts/12 00:00:00 perl
會有同樣的效果。
ps
和perl
在前台進程組中啟動,但在大多數 shell 上,ps
將是該組的領導者(如上面的輸出所示,其中和ps
的 pgid是 的 pid ),因此可以啟動自己的進程組。ps
perl
ps
perl
或者它可以更改前台進程組。基本上告訴 tty 設備將 SIGINT 傳送到其他進程組Ctrl+C
perl -MPOSIX -e 'tcsetpgrp(0,getppid) or die$!; sleep 5'
在那裡,
perl
保留在同一進程組中,但告訴終端設備前台進程組的 ID 與其父進程 ID 相同(請參閱上面的註釋)。