為什麼 Ctrl-C 不起作用?

為什麼 Ctrl-C 不起作用?

我只是敲了兩下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字元 是^Kisig已停用/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
    

    會有同樣的效果。psperl在前台進程組中啟動,但在大多數 shell 上,ps將是該組的領導者(如上面的輸出所示,其中和ps的 pgid是 的 pid ),因此可以啟動自己的進程組。psperlpsperl

  • 或者它可以更改前台進程組。基本上告訴 tty 設備將 SIGINT 傳送到其他進程組Ctrl+C

    perl -MPOSIX -e 'tcsetpgrp(0,getppid) or die$!; sleep 5'
    

    在那裡,perl保留在同一進程組中,但告訴終端設備前台進程組的 ID 與其父進程 ID 相同(請參閱上面的註釋)。

相關內容