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

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

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

^C二度繰り返されたが、その過程は続いた。

Ctrlcいつものようにプロセスを終了したらどうでしょうか?

答え1

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

  • 押されたときに通常送信されるSIGINT信号を無視するかCtrl-C(シェルのようにtrap '' INT)、独自のハンドラが終了しないことを決定するか(または時間内に終了しません)。
  • SIGINTをフォアグラウンドジョブとして送信した文字が、他の文字(stty int '^K'シェルのwithなど)であることを端末装置に通知します。
  • 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(通常)^C押すとターミナル(エミュレータ)から送信され、入力信号は無効になりません。CTRL-C

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

intr文字は無効になっています^K)。isig/dev/pts/1

完全性を期すためにプロセスがSIGINTの受信を停止する他の2つの方法がありますが、一般的に見ることができる方法ではありません。

上記ではCtrl+C、SIGINT信号はプロセス内のすべてのプロセスに送信されます。端末のフォアグラウンドプロセスグループ。通常、シェルはプロセスをプロセスグループ(シェルにマップ)に配置します。働く) そして、最終デバイスにどれがあるかを教えてくれます。展望一つ。

これで、プロセスは次のことができます。

  • 対応するプロセスグループを離れます。別のプロセスグループ(現在のプロセスグループを除くすべてのプロセスグループ)に移動する場合展望Ctrl-C1)これで、SIGINT(または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そのグループのリーダーになるので(上記の出力からわかるように、pgidはpidです)、独自のプロセスグループを起動できます。perlpspspsperlpsperl

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

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

    そこでperl同じプロセスグループに滞在し、フォアグラウンドプロセスグループのIDが親プロセスIDと同じであることを端末デバイスに通知します(上記の注意事項を参照)。

関連情報