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


9

Ctrlc終了に時間がかかるプロセスを停止するために、シェルを2回たたくだけです。

^C 2回エコーされましたが、プロセスは続行されました。

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


4
死にたくない迷惑なプログラムに対する私の解決策は通常、CTRL + Zでプログラムを一時停止してから強制終了kill -9 %することです。信号9は無視できません。また、中断信号も無視できません。CTRL + Zキーボードシーケンスは理論的には無視できますが、実際にはありません。
David Sainty 2013

@DavidSaintyサスペンド信号は無視できます(または、少なくとも停止されていません)。例:perl -E '$SIG{TSTP} = sub { say "ha ha" }; sleep 1 while 1'。おそらく別のシグナルであるSIGSTOPを考えているでしょう。
derobert 2013

ああ、そうだね:)
David Sainty 2013

回答:


13

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

  • 押したときに通常送信されるSIGINTシグナルを無視するかCtrl-Ctrap '' 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キャラクターの上にあり^Cます(通常、押しCTRL-Cて入力信号が無効にされていないときに、端末(エミュレーター)によってキャラクターが送信されます。

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

intr文字がある^Kisigのために無効になっています/dev/pts/1)。

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

するとCtrl+C、SIGINTシグナルが端末のフォアグラウンドプロセスグループのすべてのプロセスに送信されます。通常、プロセスグループ(シェルジョブにマップされます)にプロセスを配置し、フォアグラウンドデバイスをターミナルデバイスに通知するのはシェルです。

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

  • そのプロセスグループを離れます。別のプロセスグループ(フォアグラウンドプロセスグループ以外のプロセスグループ)に移動すると、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上記の出力psperlのPIDであるps)ので、perl独自のプロセスグループを開始することができます。

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

    perl -MPOSIX -e 'tcsetpgrp(0、getppid)またはdie $ !; 5フィート寝る

    そこでperlは、同じプロセスグループに留まりますが、代わりに、フォアグラウンドプロセスグループは、親プロセスIDと同じIDのグループであることを端末デバイスに伝えています(上記の注を参照)。


1
無停電通話の良い例は、応答しないハードウェアデバイスにアクセスすることです。たとえば、応答しない欠陥のあるハードディスクを使用しようとした場合hdparmsmartctl永久にハングし、CTRL + Cでそれらを強制終了することはできません。/ のstat列ps auxまたはtop/ のS列を見ると、プロセスが割り込み不可能なスリープ状態にあるかどうかがわかりますhtop- D割り込み不可能なスリープを意味します。これは必ずしも悪いことではありませんが、プロセスが大量のIOを実行していることを意味している可能性があります。
マーティンフォンヴィッティヒ2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.