最近、PIDの再利用を 防ぐことが可能であるかどうかを尋ねる質問を投稿しました 。
これまでのところ、答えはノーのようです。 (どちらでもかまいません。)
しかし、ユーザー Diego Torres Milano がその質問に回答を追加しました。ここでの私の質問は、その回答に関するものです。
ディエゴは答えた、
PIDを再利用するのが怖い場合は、他の回答で説明されているように待てば発生しませんが、
echo 4194303 > /proc/sys/kernel/pid_max
あなたの恐怖を減らすために;-)
ここでDiegoが4194303
という数字を使用した理由は実際にはわかりませんが、それは別の質問です。
私の理解は、次のコードに問題があったことです:
for pid in "${PIDS[@]}"
do
wait $pid
done
問題は、配列に複数のPIDがあり、forループが配列の各PIDでwait
コマンドを順番に実行することですが、プロセスが同じ順序で完了すると予測できません。 PIDはこの配列に格納されます。
すなわち;次のが発生する可能性があります:
wait
は、配列インデックス0のPIDが終了すると終了しますwait
が現在待っているneverPIDを再利用して実行されたプロセスは終了します。おそらくそれは、システム管理者が開始したメールサーバーまたは何かのPIDです。wait
は、次に深刻なLinuxバグが見つかり、システムが再起動されるか、停電になるまで待機し続けますディエゴは言った:
他の答えが説明するようにあなたが待つならば、それは起こりません
すなわち;私が上で述べた状況は起こり得ないということです。
ディエゴは正しいですか?
または、ディエゴは正しくありませんか?
PIDがバックグラウンドで起動されたプロセスのPIDであることを認識していない限り、この質問は混乱を招く可能性があることに気付きました。すなわち;
my_function &
PID="$!"
PIDS+=($PID)
オプションを見てみましょう。
for i in 1 2 3 4 5; do
cmd &
done
wait
これは単純であるという利点がありますが、マシンをビジー状態に保つことはできません。古いジョブが完了したときに新しいジョブを開始したい場合は、できません。すべてのバックグラウンドジョブが完了するまで、マシンの使用率は低下します。その時点で、ジョブの新しいバッチを開始できます。
関連するのは、wait
に複数の引数を渡して、ジョブのサブセットを待機する機能です。
unrelated_job &
for i in 1 2 3 4 5; do
cmd & pids+=($!)
done
wait "${pids[@]}" # Does not wait for unrelated_job, though
for i in 1 2 3 4 5; do
cmd & pids+=($!)
done
for pid in "${pids[@]}"; do
wait "$pid"
# do something when a job completes
done
これには、ジョブが完了した後に作業を行えるという利点がありますが、ジョブotherよりも問題があります$pid
が最初に完了し、$pid
は実際に完了します。ただし、実際に待機する前に完了した場合でも、個々のジョブの終了ステータスを取得します。
bash
4.3以降)for i in 1 2 3 4 5; do
cmd & pids+=($!)
done
for pid in "${pids[@]}"; do
wait -n
# do something when a job completes
done
ここでは、aジョブが完了するまで待機できます。つまり、マシンをできるだけビジー状態に保つことができます。唯一の問題は、アクティブなプロセスのリストを取得するためにjobs
を使用してそれをpids
と比較することなく、必ずしも完了したwhichジョブがわかっていないことです。
シェル自体はジョブ分散を行うための理想的なプラットフォームではありません。そのため、バッチジョブを管理するために設計された多数のプログラムがあります:xargs
、parallel
、slurm
、 qsub
など.
これは古いですが、pidの衝突が原因で遅延wait
がランダムな無関係のプロセスを待機するというシナリオは、直接対処されていません。
カーネルレベルでは不可能です。親プロセスがwait(2)
¹を呼び出す前に、子プロセスまだ存在するが機能します。子がまだ存在しているため、Linuxは再利用するのではなくPIDを使い果たします。これは、いわゆるゾンビプロセスまたは「デファクト」プロセスで時々現れます。これらは、終了したが、親によってまだ「取得」されていない子です。
シェルレベルでは、子プロセスを取得するためにwait(1)
¹を呼び出す必要はありません-bash
がこれを自動的に行います。私は確認していませんが、ずっと前に終了した子pidに対してwait $pid
を実行すると、bash
は、その子をすでに取得していて、何も待たずにすぐに情報を返すことに気づきます。
_ wait(N)
表記は、APIレイヤーを明確にするために使用される規則です-Nは、コマンド/関数が配置されているマニュアルのセクションを指します。この場合、次のようになります。
wait(2)
:syscall-man 2 wait
を参照wait(1)
:シェルコマンド-man 1 wait
またはhelp wait
を参照各マニュアルセクションの内容を知りたい場合は、man N intro
を試してください。