競合状態なしで終了する子プロセスではなく、プロセスにシェルコマンドを関連付けるにはどうすればよいですか?

競合状態なしで終了する子プロセスではなく、プロセスにシェルコマンドを関連付けるにはどうすればよいですか?

時には、プロセスが完了したら別のコマンドを実行する必要があることに気づきます。同じシェルにある場合(そして-Zを制御できます)すでに実行中のprog1に「&& prog2」を追加できますか?多くの良い解決策が提供されています。しかし、子プロセスの場合にのみ機能します。

少なくとも同じユーザーIDを共有するプロセスにはかなり標準的なイディオムがあります。これはシェルで次のようになります。

while kill -s 0 $pid 2> /dev/null; do sleep 1; done

/procLinuxなどのシステムでは、[ -d /proc/$pid ]代替を使用してkill同じユーザーID要件を免除できます。

しかし、どちらも競争条件があります。その間、プロセスは終了し、sleep新しいプロセスは同じPIDを取得できます。したがって、ループは、関心のあるプロセスが実際に終了したことを認識しないまま継続します。

シェルスクリプトから競合状態を削除する方法はありますか?

答え1

Linux によって異なる場合もあれば、他の場合は/proc動作が異なる場合もありますが、Linux では次のことができます。

(   # subshell to preserve CWD
    cd /proc/$pid || exit
    [ "$expected_path" = "$(readlink exe)" ] || exit # optional, and can do more checks
    while [ -d . ]; do sleep 1; done
)

.プロセスが終了すると、作業ディレクトリは無効になり、もう存在しません。しかし、新しいプロセスがそのpidを採用した場合いいえ再び有効です。プロセスが以前に終了した場合(そしてpidが未使用のままである場合)、cdこれはcd失敗し、サブシェルは終了します。以前にpidを再利用した場合はcd成功しますが、「オプションの」チェック(LJKimsに感謝します)でこれをキャッチできることを願っています。したがって、検査が可能な競合の非常に短い範囲を捕捉する限り、競合条件はない。テストするには、次のものを使用できます。

# shell 1
$ sleep 10 &
[1] 26453
$ cd /proc/26453

# shell 2 (must be bash for BASHPID)
for ((i=0; i<200000; ++i)) do ( if [ 26453 -eq $BASHPID ]; then echo "I am have the pid — sleeping 60"; sleep 60; echo "done sleeping"; fi ); done
I have the pid — sleeping 60

# back to shell 1
[ -d . ]; echo $?
1

したがって、新しいPIDが26453であっても、興味のある睡眠が終了したことがまだわかります。

答え2

プロセスを停止できると仮定すると(これは言及したctrl+を介してz)、これは非競争的なモック方法です&& prog2(実際にはより正確には; prog2終了ステータスを確認するのではなく追加できます)。

PIDを探してください。別の端末を開いて実行

strace -f -e trace=exit_group -p $PID && prog2

その後、プロセスを再開します。

答え3

おそらく、PIDだけに基づいてプロセスを監視したくないでしょう。つまり、おそらくプロセスが何であるかを知っています。 /proc/<pid>/cmdline の内容を監視して、内容が存在しなくなった場合や予想と一致しない場合は、コマンド/ジョブを実行できますか?

答え4

たぶんファイルをロックするのは良い方法です。子プロセスに渡された文字列を含む、ロックファイル/ロックファイル名の一部に入れることもできます。

ロックされたファイルは、プロセスが実際に終了している間に削除される可能性があります。その後、名前または内容でロックファイルを見つけ、PIDをロックファイルに入れることができます。ロックファイルがあり、まだ実行中の場合は、ファイルからPIDを取得できますか?一方、ロックファイルが消えると、プロセスは完了です。

関連情報