親プロセスブロックは、ゾンビ子プロセスの出力を読み取ろうとします。

親プロセスブロックは、ゾンビ子プロセスの出力を読み取ろうとします。

設定:Python(3.6)スクリプトがあります( "オペレーター")はbashスクリプト("と呼ばれる)を実行します。プランジャー") は、標準サブプロセスの方法でサブプロセスから標準出力を収集して記録します。プランジャースクリプト自体は簡単です。別のスクリプト/プログラムを呼び出して、適切に複雑な3つのタスクを実行します。 a) 複数のデーモンを終了し、b) いくつかの管理タスクを実行し、c) いくつかの新しいデーモンを起動してから終了します。システム自体には特に奇妙なことはありません。標準のrpmで動作する通常の古いCentOSです。

質問:いつ。 。 。いつプランジャースクリプトはaとbの部分のみを実行し、すべてが期待どおりに機能します。プランジャー(cなし)完了するまで実行され、オペレーターすべての出力を収集し、残りの作業を続けます。しかし、cステップを含めるとプランジャー正しく実行され、オペレーターすべての出力が収集されますが(一度に少しずつ読み取られると)、プランジャがシャットダウンしたことにまったく気づかず、出力の読み取りを完了しないため、制御は再送されません。オペレータースクリプト。

簡単な例:

return subprocess.check_output("plunger")  # doesn't complete with the real plunger script

観察結果:

  • 走るプランジャーインタラクティブシェルでは常にうまく機能します。
  • これプランジャープロセスがしなければならないすべてのタスクを実行して終了しました。
  • psを実行して表示プランジャーbashプロセスをゾンビとして使用する(「プランジャ」)
  • Popenを使用して1行ずつ読み込むと、予想されるすべての行が出力され、改行で正しく終了することを意味します。
  • Popenを使用してpoll()を使用してプロセスの状態を確認すると、Noneのみが解放されます。
  • 子プロセスが終了していないか、読み取るバイトがまだあるかのように動作します。シャットダウンされた唯一のPIPEストリームがstdoutであり、stdoutブロックから読み取られる場合も同様です。

推測: 私の推測では、最後のステップで作成された新しいバックグラウンド(デーモン)プロセスが何らかの方法でstdoutストリームを継承して開いたままにしているため、実行されたプランジャスクリプトが出力され終了しても、一部の未知のプロセスがそれを維持するため、オペレータスクリプトは続行できますありません。

質問: 私の推測は可能ですか(または可能性がありますか?)そうでなければ、何をさらに見つけることができますか?それでは、どのように保護する必要がありますか?オペレーターそして/またはプランジャーダウンストリームで私のストリームを乱用しますか?

PS: 私の恐ろしいhacky fuglyソリューションは次のとおりです。プランジャー作業を終えた後、ユニークなラインを鳴らして広げるときオペレーター見れば殺すプランジャープロセス。この記事を書くだけで気分が汚れます。

編集と結論: 私の推測は正しいです。問題はPythonや実際にはbashとは関係がなく、フォークの仕組みにもっと関連しています。以下は最小限の例です。

$ (date; (sleep 5 &); date); date
Wed Feb  6 12:46:27 EST 2019
Wed Feb  6 12:46:27 EST 2019
Wed Feb  6 12:46:27 EST 2019
$ (date; (sleep 5 &); date) | cat; date
Wed Feb  6 12:46:51 EST 2019
Wed Feb  6 12:46:51 EST 2019
Wed Feb  6 12:46:56 EST 2019  # <- five second gap!
$ (date; ((sleep 5 &)>/dev/null); date) | cat; date
Wed Feb  6 12:47:13 EST 2019
Wed Feb  6 12:47:13 EST 2019
Wed Feb  6 12:47:13 EST 2019
# this works too
$ (date; (sleep 5 >/dev/null &); date) | cat; date
Wed Feb  6 13:11:24 EST 2019
Wed Feb  6 13:11:24 EST 2019
Wed Feb  6 13:11:24 EST 2019

私はこれから実際に保護する方法がないと思います。実際の犯人は、デーモンを起動するためにCによって呼び出されたスクリプトがパイプを開いたままにしないように、出力を別のものにリダイレクトする必要があることです。

ベストアンサー1

私は質問の最後の部分(現在編集済み)でこの質問に答えました。

簡単に言えば、いくら深くネストされていても、バックグラウンドプロセスを開始するすべてのエントリは出力ストリームをキャプチャし、子プロセスを完全にシャットダウンするのを防ぐことができます。私が思いついた解決策は次のとおりです。(a)デーモンの起動出力を/ dev / nullにリダイレクトするか、(b)デーモンの起動出力をファイルにリダイレクトし(必要に応じて)、そのファイルを別々に監視することです。直系の子供が終了します。

おすすめ記事