パイプラインの他のプロセスを終了する(プログラミング方式)

パイプラインの他のプロセスを終了する(プログラミング方式)

私がこれを持っているとしましょう:

node a.js | node b.js | node c.js

a.jsが死んでいる場合、b.jsを殺すことはできますか?その逆はどうですか?このパイプを構築すると、他のプロセスが終了/終了したときに1つのプロセスが必ず終了/終了するわけではありません。一人の人が死んだらどうやって殺すことができますか?

答え1

存在する:

cmd1 | cmd2

cmd2完了すると自動的に終了しませんが、cmd1標準入力ではファイルの終わりが表示されます。これは通常パイプラインが終了する方法です。

存在する:

echo foo | sed s/o/e/g

sedecho現在、標準入力から読み取ることができないことがわかったので、終了後に終了します。

シャットダウン時にcmd1シャットダウンを試みることができますが、cmd2パイプに記録されているすべてのエントリをcmd2まだ読んでいない場合はどうなりますか?cmd1

cmd2最初に死ぬと自動的cmd1に死ぬことはありませんが、次に(現在破損している)パイプに書き込もうとすると(SIGPIPEを使って)死にます。

パイプラインは次のとおりです。

yes | head

終了(最初の10行を読み取り、印刷してから終了し、yesパイプに最初に書き込むと終了します)。head

パイプのもう一方の端にあるプロセスを本当に終了したい場合は、パイプのもう一方の端にどのプロセスがファイル記述子を持っているかを理解するための移植可能な方法はありません。

/proc/*/fdLinuxでは、パイプの末尾のfdにあるパイプと同じinodeを持つファイルを見つけることができ、シンボリックリンク自体に対する権限はパイプのどちらの端かを示します。

$ (ls -lLi /proc/self/fd/3; ls -l /proc/self/fd/3) 3>&1 >&2 | (ls -Lil /proc/self/fd/0; ls -l /proc/self/fd/0)
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/3|
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/0|
l-wx------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/3 -> pipe:[224052]
lr-x------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/0 -> pipe:[224052]

同じパイプ inode の場合、書き込み側の fd にw権限があり、読み取り側の fd にr権限があります。

たとえば、zsh次のコマンドを使用して、パイプの読み取り端にfdがあり、パイプのもう一方の端がfd 3にあるプロセスのpidを取得できます。

pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
pids=(${(u)pids}) # unique

例:

$ (pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
  pids=(${(u)pids}); ps -fp $pids) 3>&1 >&2 | tr a b
UID        PID  PPID  C STIME TTY          TIME CMD
chazelas 24157 11759  0 23:41 pts/1    00:00:00 tr a b

したがって、次のことができます(まだLinuxでを使用してzsh)。

run_and_kill_the_other_end() {
  setopt localoptions localtraps
  trap : TERM
  "$@"
  local ret=$?
  local -aU pids
  if [ -p /dev/stdout ]; then
    pids=(/proc/<2->/fd/<0-9>(Nf{u+r}e{'[[ $REPLY -ef /dev/stdout ]]'}-p:h:h:t))
    exec >&- # give the right end a chance to see eof and act upon it
  fi
  [ -p /dev/stdin ] &&
    pids+=(/proc/<2->/fd/<0-9>(Nf{u+w}e{'[[ $REPLY -ef /dev/stdin ]]'}-p:h:h:t))
  (($#pids)) && kill $pids 2> /dev/null
  return $ret
}

それから:

run_and_kill_the_other_end node a.js | run_and_kill_the_other_end node b.js

しかし、これは望む作業ではないかもしれません。たとえば、

$ run_and_kill_the_other_end seq 100 |
    run_and_kill_the_other_end sort |
    run_and_kill_the_other_end wc -l
0

sortソートされた出力を作成する前に終了しました。wc -l脱出してみてください。

猶予期間に遅延を挿入できますが、遅延期間はどのくらいですか?たとえば、後ろsleep 0.1に追加すると、次のようexec >&-に表示されます。

$ run_and_kill_the_other_end seq 100 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
100
$ run_and_kill_the_other_end seq 10000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
10000
$ run_and_kill_the_other_end seq 100000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
0

これはパイプラインの終了が無条件に遅れるという意味でもあります。タイムアウトのある「s」を使用してzshこれを改善できます。zselect

関連情報