私はそれを使用していますUbuntu14.04理解できない動作が発生します。
- コマンドを実行します
yes
(デフォルトのシェルでは:吹く) - CtrlZ停止するには入力してください。
yes
- ランニング
jobs
。出力:
[1]+ Stopped yes
kill -9 %1
停止するまで走ってくださいyes
。出力:
[1]+ Stopped yes
- ランニング
jobs
。出力:
[1]+ Stopped yes
これは、3.16.0-30-generic
パラレル仮想マシンで実行されるUbuntuにあります。
kill -9
私のコマンドが終了しないのはなぜですか?はい注文する?私の考えでは信号を殺す捕まったり無視することはできませんか?どうやって終了できますか?はい注文する?
答え1
プロセスを一時停止するためのシグナルがブロックされました。ターミナルから:
$ yes
...
y
y
^Zy
[1]+ Stopped yes
2番目のターミナルで:
$ killall yes
最初の端末で:
$ jobs
[1]+ Stopped yes
$ fg
yes
Terminated
しかし、SIGKILL
止めることはできません。 2番目の端末で同じことを行うと、killall -9 yes
端末からすぐに結果が得られますyes
。
[1]+ Killed yes
したがって、kill -9 %1
プロセスをすぐに終了しないbash
場合は、プロセスを破棄するまで信号が実際に送信されないか、fg
カーネルでバグが見つかりました。
答え2
慌てないでください。
奇妙なことは起こりません。ここにカーネルのバグはありません。これは、Bourne Againシェルとマルチタスクオペレーティングシステムの完全に正常な動作です。
覚えておくべきこと自殺を扱う、または応答することもできますSIGKILL
。ここで何が起こっているのかは、Bourne Againシェルが何かを処理しているということです。今後ただ自分を殺す過程が実際には自分を殺したと自らに言っただけです。
yes
停止点で何が起こるかを検討し、SIGTSTP
Bourne kill
Againシェルを使用してこのコマンドを実行しました。
- シェルがプロセス
SIGKILL
に転送されます。yes
- 平行に:
- プロセス
yes
が実行され、すぐに終了するようにスケジュールされます。 - Bourne Againシェルは引き続き別のプロンプトを発行します。
- プロセス
あなたが1つを見て、他の人が別のものを見るのは、実行する準備ができた2つのプロセス間の単純な競争によるものです。ここでは、勝者は完全にマシン間で、そして時間の経過とともに変化することに依存します。 CPUが仮想であるという事実と同様に、システムの負荷も影響します。
興味深い場合は、ステップ2の詳細は次のとおりです。
- Bourne Againシェルが続きます。
kill
内部的に組み込まれたコマンドの一部として、作業テーブルのエントリを次のように表示します。通知メッセージを印刷する必要があります。次の利用可能なポイントで。- コマンドを完了し
kill
てプロンプトを印刷する前に、ジョブに関する通知メッセージを印刷する必要があるかどうかを再確認してください。 - プロセス
yes
は自分で終了する機会がなかったので、シェルに関する限り、操作はまだ中止されます。したがって、シェルはジョブの「中止」ジョブステータス行を印刷し、対応する通知保留フラグをリセットします。 - プロセス
yes
がスケジュールされ、それ自体で終了します。 - カーネルは、コマンドラインエディタを実行していたシェルに、プロセス自体が終了したことを通知します。シェルは状態変更を記録し、ジョブを保留中としてマークします。
- enterループプロンプト印刷をもう一度押すだけで、シェルが新しいジョブステータスを印刷する機会を得ることができます。
ポイントは次のとおりです。
- プロセス自体が終了します。
SIGKILL
これは魔法ではありません。プロセスは、ページエラー、(ネストされていない)割り込み、およびシステムコールの終了時に発生するカーネルモードからアプリケーションモードに戻るときに保留中の信号を確認します。唯一の特別なことは、カーネルが即時かつSIGKILL
無条件の自殺以外の対応操作を許可せず、アプリケーションモードに戻らないことです。重要なことは、プロセスをカーネルからアプリケーションモードに切り替える必要があることです。そして信号に応答して実行するようにスケジュールされています。 - 仮想CPUはホストオペレーティングシステムのスレッドです。ホストが仮想 CPU 実行をスケジュールしたという保証はありません。ホストオペレーティングシステムも魔法ではありません。
- ジョブの状態が変わると、通知メッセージは印刷されません(使用しない限り
set -o notify
)。シェルが実行サイクルの次のポイントに達すると、印刷され、保留中の通知があることを確認します。 - 通知保留フラグは、シグナルハンドラ
kill
によって1回、2回設定されます。SIGCHLD
つまり人々が見ることができるという意味だ。二つyes
プロセス自体が終了するように再スケジュールされる前にシェルが実行されると、メッセージが表示されます。 1つは「中止」メッセージ、もう1つは「終了済み」メッセージです。 - 明らかに、この
/bin/kill
プログラムはシェルの内部作業テーブルにアクセスできないため、そのような動作を見ることはできません/bin/kill
。通知保留フラグはハンドラによって一度だけ設定されますSIGCHLD
。 - 同じ理由で別のシェルで処理している場合、
kill
この動作は表示されません。yes
答え3
あなたが観察しているのは、このbashバージョンのバグです。
kill -9 %1
ジョブは実際にはすぐに終了します。を使用してこれを観察できますps
。 bashプロセスを追跡してシステムコールが呼び出されるタイミングを確認し、サブkill
プロセスを追跡して信号を受信して処理するタイミングを確認できます。もっと興味深いのは、この過程で何が起こるのかを直接見て見ることができるということです。
bash-4.3$ sleep 9999
^Z
[1]+ Stopped sleep 9999
bash-4.3$ kill -9 %1
[1]+ Stopped sleep 9999
bash-4.3$ jobs
[1]+ Stopped sleep 9999
bash-4.3$ jobs -l
[1]+ 3083 Stopped sleep 9999
bash-4.3$
他の端末から:
% ps 3083
PID TTY STAT TIME COMMAND
3083 pts/4 Z 0:00 [sleep] <defunct>
子プロセスはゾンビ。それは死んだ。残りはプロセステーブルのエントリだけです(ただし、メモリ、コード、開いたファイルなどはありません)。その項目は、親が通知して通過するまで保持されます。wait
システムコールまたはその兄弟のいずれか。
対話型シェルは、死んだ子プロセスを確認し、プロンプトを印刷する前にそれをキャプチャする必要があります(特に設定しない限り)。このバージョンのbashでは、次の場合にこれを行うことはできません。
bash-4.3$ jobs -l
[1]+ 3083 Stopped sleep 9999
bash-4.3$ true
bash-4.3$ /bin/true
[1]+ Killed sleep 9999
コマンドがプロンプトを印刷した直後にbashが "Killed"を報告することを期待できますが、kill
競合状態のためこれは保証されません。信号は非同期で転送されます。kill
カーネルがシグナルを転送するプロセスを決定するとすぐに、システムコールはシグナルが実際に転送されるのを待たずにすぐに返されます。 bashは子プロセスの状態を確認し、まだ死んでいないことを確認し(子プロセスの終了を報告していwait4
ない)、プロセスがまだ停止していることを印刷する時間を持つことができ、実際に発生します。エラーは、次のプロンプトの前にシグナルが送信されたが(ps
プロセスが終了したことを見て)、bashがまだ呼び出されていないwait4
ことです(私たちが見ることができるように、これはまだタスクが「中断された」と報告されているためですが、残っているため、実際に bash はwait4
次に呼び出す必要がある場合にのみゾンビを取得し、他の外部コマンドを実行します。
エラーは断続的に発生し、bashを追跡するときにそれを再現することはできません(おそらくbashが迅速に反応する必要がある競合状態であるため)。 bash 検査の前にシグナルが転送されると、すべてが期待どおりに発生します。
答え4
システムに何か奇妙なことが起こっている可能性があります。私の-9
レシピでは、以下があるかどうかにかかわらずうまくいきます。
> yes
...
^Z
[1]+ Stopped yes
> jobs
[1]+ Stopped yes
> kill %1
[1]+ Killed yes
> jobs
>
pidを取得し、jobs -p
それを殺そうとしますroot
。