Ctrl-C が機能しなかったのはなぜですか?

Ctrl-C が機能しなかったのはなぜですか?

Ctrlc完了するまでに長い時間がかかっているプロセスを停止しようとして、シェルを 2 回実行しました。

^C2回繰り返しましたが、プロセスはそのまま続行されました。

Ctrlc通常どおりにプロセスを終了しなかったのはなぜですか?

答え1

プロセスでは以下を選択できます。

  • 通常、押すと送信される SIGINT シグナルを無視しますCtrl-C(シェル内の場合などtrap '' INT)。または、終了しないことを決定する (または適切なタイミングで終了できない) 独自のハンドラーを用意します。
  • 端末デバイスに、フォアグラウンドジョブに SIGINT が送信される原因となる文字が別の文字 (stty int '^K'シェル内の文字など)であることを伝えます。
  • 端末デバイスに信号を送信しないように指示します (stty -isigシェル内の場合と同様)。

または、中断できないシステム コールの途中など、中断できない場合もあります。

Linux(比較的新しいカーネル)では、プロセスが無視されているか、または取り扱いSIGINTの出力を見て

$ kill -l INT
2
$ grep Sig "/proc/$pid/status"
SigQ:   0/63858
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 0000000000000000

SIGINT は 2 です。上記の SigIgn の 2 番目のビットは 1 であり、SIGINT は無視されることを意味します。

これを自動化するには、次の操作を実行します。

$ 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であり、入力信号は無効になっていません。^CCTRL-C

$ stty -a < /dev/pts/1
[...] intr = ^K [...] -isig

(intr文字は であり^Kisigでは無効です/dev/pts/1)。

完全を期すために、プロセスが SIGINT の受信を停止する方法が他に 2 つありますが、これは通常は見られない方法です。

するとCtrl+C、SIGINTシグナルがすべてのプロセスに送信されます。端末のフォアグラウンドプロセスグループプロセスをプロセスグループに配置するのは通常シェルです(シェルにマップされます)。仕事)を端末に伝え、前景1つ。

プロセスは次のことが可能になります。

  • プロセスグループを離れる。別のプロセスグループ(現在のプロセスグループ以外のプロセスグループ)に移動すると、前景1 の場合、SIGINT を受信しなくなりますCtrl-C(SIGTSTP、SIGQUIT などの他のキーボード関連のシグナルも受信しなくなります)。ただし、(バックグラウンド プロセスと同様に) 端末デバイスから読み取り (端末デバイスの設定によっては書き込みも可能) を試行すると、中断される可能性があります。

    例:

    perl -MPOSIX -e 'setpgid(0,getppid) or die "$!"; sleep 10'
    

    は、 で割り込みできませんでしたCtrl-C。上記は、perl親プロセス ID と同じ ID を持つプロセス グループに参加しようとします。一般に、その ID を持つプロセス グループが存在するという保証はありません。ただし、ここでは、perl対話型シェルのプロンプトでそのコマンドが単独で実行される場合、ppid はシェルのプロセスになり、シェルは通常、独自のプロセス グループで開始されます。

    コマンドがまだプロセス グループ リーダー (そのフォアグラウンド プロセス グループのリーダー) でない場合は、新しいプロセス グループを開始しても同じ効果が得られます。

    例えば、シェルによっては、

    $ 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フォアグラウンド プロセス グループで開始されますが、ほとんどのシェルでは がpsそのグループのリーダーになります (上記の出力でわかるように、と のps両方の pgid はの pid です)。そのため、 は独自のプロセス グループを開始できます。psperlpsperl

  • または、フォアグラウンドプロセスグループを変更することもできます。基本的には、ttyデバイスに、他のプロセスグループにSIGINTを送信するように指示します。Ctrl+C

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

    そこでは、perl同じプロセス グループに残りますが、代わりに、フォアグラウンド プロセス グループの ID が親プロセス ID と同じであることをターミナル デバイスに伝えます (これについては上記の注記を参照してください)。

関連情報