婦人声明:この問題は予想よりはるかに長かった。 5つのサブ質問に分けました。本を開く前に考えを整理しようとしましたが、今は混乱する部分が多すぎます。
私の考えを明確にしてみてはいかがですか?正しくBashで処理堅い道、偶然発見したGregのwiki記事。最初からではなく、このようなフレーズがあります。
何かをしたい子プロセスを開始する親プロセスにまだある場合、これは完璧です。以下に説明する理由により、PIDが子プロセス(死亡または生存)であることを保証できます。これを使用
kill
して、信号の送信、終了、またはまだ実行中であることを確認できます。これを使用してwait
終了するのを待つか、終了した場合は終了コードを取得できます。
上記のページの最後に理由は以下に説明されています見つけることができます。
各UNIXプロセスに親プロセス。親プロセスは自分自身を開始したプロセスですが、新しい
init
プロセスが終了する前に親プロセスが終了すると、そのプロセスに変更される可能性があります。 (つまり、init
孤児プロセスが選択されています。)この親/子関係を理解することは、UNIXの信頼性の高いプロセス管理の鍵であるため、重要です。プロセスが終了した後、プロセスのPIDは、親プロセスが終了したことをwait
確認し、終了コードを取得するためにPIDを取得するまで使用のために解放されません。親プロセスが終了すると、プロセスは親プロセスに戻り、init
これを実行します。これは主な理由の1つです。親プロセスが子プロセスを管理している場合、子プロセスが終了しても親プロセスがタスクを完了するまで、他の新しいプロセスが誤って子プロセスのPIDをリサイクルしないことを確実にすることができます
wait
。 PIDを確認し、子供が死んだことを発見しました。これは、アクティブプロセスであるか「ゾンビ」プロセスであるかに関係なく、子プロセスのPIDが常に子プロセスを指すことを親プロセスに保証します。他の人はそのような保証を受けていません。残念ながら、この保証はシェルスクリプトには適用されません。シェルはサブプロセスを積極的に取得し、スクリプトが呼び出すメモリに終了ステータスを保存します
wait
。しかし、サブプロセスはすでに収集されています。今後に電話すると、wait
PIDを持っているゾンビはありません。カーネルはPIDを自由に再利用でき、保証違反です。
私は上記の段落を何度も読んでいますが、まだ後ろに隠されたメッセージを正しく理解しているかどうかはわかりません。
質問1:2番目の長い引用、特に最後の引用では、私はシェル(Bashにのみ興味があります)スクリプトで変数に保存されたPIDがまだバックグラウンドプロセスを参照しているかどうか100%確信できないと結論付けました。始めました。他のプロセス(子プロセスでもない)に対してカーネルで再利用できるからです。これは正しいですか?上記の保証はシステムのどの部分に適用されますか?
質問2:2番目の引用符の最後の段落は、最初の引用文と矛盾するようです。全体的に本当ですか?シェルスクリプトからそれ「まだ子プロセスを開始した親プロセスにいる場合は、[...] PIDが子プロセス(死亡または生きている)であることを保証できます。?
質問3:Webでそのトピックに関する他の情報源を見つけましたが、いつものように、事実と不正確な声明を区別することは困難です。いくつかの確認を受けましたが、さらに質問があります。引用するこれそしてこれ問題は、バックグラウンドでスクリプトでプロセスを開始し、PIDを変数に保存し、何かを実行してからPIDを組み合わせて終了wait
コードを取得したりkill
シグナルを送信したりする素朴なアプローチが失敗する可能性があることです。 PID はカーネルで再利用されます。普遍的なレシピはありますか?
質問4:私も見つけました。このコメントこれは、「バックグラウンド(プロセス)が戻りコードをファイルに保存し、親プロセスがファイルからインポートできるようにします」を意味します。これが信頼できる方法ですか?
質問5:使用時の注意事項はありますかwait -n
? PIDを明示的に提供しないと(再利用可能)、wait
エラーは発生しないと思います。しかし、そうだBash v4.4では、ジョブ制御を有効にしたときに-n
このオプションがwait
役に立ちました。set -m
Bash v5.0でも同じですか?
ボーナス質問: この回答内容はGregのwikiに似ています。
pidを使用して信号を送信するのが安全な場合は1つだけです。これは、ターゲットプロセスがシグナルを送信するプロセスの直接的なサブプロセスであり、親プロセスがまだシグナルを待っていない場合です。
何ですか直接子供?子供とはちょっと違いますか?
ベストアンサー1
...シェル(Bashにのみ興味があります)スクリプト内の変数に格納されているPIDが私が起動したバックグラウンドプロセスを参照し続けるかどうか100%確信できません。他のプロセス。 ..
正しい。
シェルがプログラムされた方法に応じて、シェルは子wait()
プロセスが終了するとすぐにそれを呼び出し(終了状態を内部状態の一部として保存)、他のプロセスで再利用できるようにPIDを解放します。
これがシェルスクリプトの場合ですか?「まだ子プロセスを開始した親プロセスにいる場合は、[...] PIDが子プロセス(死亡または生きている)であることを保証できます。?
いいえ、これは本当ではありません。
前述のように(および引用符で)シェル自体が子プロセスをただちに収集するため、デフォルトではこの保証は破られます。
バックグラウンドでスクリプトを使用してプロセスを起動し、対応するPIDを変数に保存し、いくつかのタスクを実行し、スタンバイでPIDを使用して終了コードを取得するか、Killを使用してシグナルを送信します。この簡単なアプローチは重複する可能性があります。失敗したPIDを使用するコア。
シェルを使用すると、これが最善です。
usingはwait
実際には問題ではありません。子プロセスが死んでいる可能kill
性があり、PIDが再利用され、他のプロセスを殺しているからです。
wait
それ自体はシェルで実装されています。子プロセスを取得すると、その終了状態がメモリに保存されるため、そのwait
情報を組み込み機能に使用できます(まだ実行中の子プロセスを待つことも含まれます)。
さらに、カーネルは通常PIDの再利用を避けようとし、少なくともPIDの再利用を遅らせようとします。これは、正確には、場合によってはPIDが再利用されないという保証がないためです。したがって、カーネルはこのような状況を最小化しようとします。信号が誤ったプロセスに転送されます。
普遍的なレシピはありますか?
信頼性のために?
はい、CまたはPython、Perl、Rubyなどを使用してバックグラウンドプロセスを開始するコードを実装します。シェルではありません。
デフォルトでは、シェルのように子をインポートしないため、この問題はありません。したがって、明示的にこれを行う必要があります。
または、システム管理者(systemdなど)を使用してバックグラウンドプロセスを開始することを検討してください。
「バックグラウンド(プロセス)が戻りコードをファイルに保存し、親プロセスがファイルからインポートできるようにします。」これが信頼できる方法ですか?
おそらく。
そこに干渉がないことを保証することはできません。そのプロセスのみを書き込むことができ、他のプロセスは書き込めない場所を見つけることは困難です。
これは呼び出しの場合には適用されず、wait
カーネルは他のプロセスによって偽造されないようにします。
また、wait
呼び出しによってプロセスが終了したか、またはクラッシュしたことを知らせることもできます。この場合、戻り状態をファイルに書き込むプロセス自体に依存している場合は、不完全な情報を取得できます。
さらに、PIDの再利用の主な問題は、PIDを殺すことです。これは戻りコードをインポートすると実際には問題にならず、ファイルを使用して戻りコードを保存してもwait
問題は解決しません。kill
使用時の注意事項はありますか
wait -n
?
まさか。wait
AFAICTは信頼性が高く、PIDの再利用の影響を受けません。これは、シェルが子プロセスを取得するときに使用しているPIDと戻りコードを含むその情報を内部状態の一部として保持するためです。
に電話すると、wait
このフォームから情報を入手できます。
最初のインスタンスが呼び出される前に、同じシェルの新しいバックグラウンドサブプロセスでPIDを再利用すると、潜在的な問題がある可能性があると思います。wait
その時点から、テーブルに競合が発生し、2つの別々のオブジェクトで終わります。同じPIDを持つバックグラウンドプロセス。これは極端なケースです。とても珍しいと思いますが、本物かもしれません。この場合、シェルが何をしているのかはわかりません。シェルの実装によって異なり、バージョンごとに異なる場合があります。
ただし、前述のように、この問題に対する実際の解決策は、PIDの保証を維持することであり、これらの保証が重要な場合はシェル以外のものを使用することです。
何ですか直接子供?子供とはちょっと違いますか?
まるで子供のように。
これはあなた自身の分岐子です。
たとえば、子プロセスがプロセスを分岐し、そのプロセスのPIDを渡す場合、そのプロセスが持続するという保証はもはやありません。
このプロセスを収集することは子供の仕事であるため、子供はPIDを収集するまでPIDが再利用されないようにすることができます。それはあなたではありません。
もちろん、親プロセスは子プロセスと協力してこの保証を拡張できます。たとえば、子プロセスの PID を照会して、依然として予想されるプロセスであることを確認し、子プロセスを収集するのを防ぎ、シグナルを送信します。 、またはおそらく子供に依頼し(保護者と一緒に)、親に代わって信号を送信します。
これが問題解決に役立つことを願っています。