
だから私はかなり長い間働いてきたDebian 7のBASHサービスに問題があり、そのFIFOがランダムに問題を引き起こし始めているようです。これは古典的なfifoの使用例に基づいており、数ヶ月間うまく機能しましたが、今日は突然問題が発生し始めました。このようなことが起こるたびに、最初に下した結論とはいつもまったく違うようで、私が持っていることを見せてくれる。
私が言ったように、名前付きパイプで読み書きするコードはかなり標準的です。簡単なバージョン(150行程度)を作ってお見せしなければならないと思いましたが、もちろんうまく動作するのに理由はわかりません。参照用に要約されたバージョンは次のとおりです。
#--------------------------------Writer Script--------------------------------------#
#!/bin/bash
fifoIn=".../path/fifoIn"
#Read user input
IFS='' #Changed IFS so that spaces aren't trimmed from input
while true; do
read -e line
printf "%b\n" "$line" >&4
done 4>"$fifoIn"
exit 0
#--------------------------------Reader Script--------------------------------------#
#!/bin/bash
fifoIn=".../path/fifoIn"
LogFile=".../path/srvc.log"
[ -d ".../path" ] || mkdir -p ".../path"
[ -e "$fifoIn" ] || mkfifo "$fifoIn"
printf "%b\n" "Flushing input pipe" >> "$LogFile"
dd if="$fifoIn" iflag=nonblock of=/dev/null >/dev/null 2>&1
while true; do
if read -t 0.1 -a str; then
printf "\n%s\n" "<${str[*]}>"
case "${str[0]}" in
"foo")
printf '%b\n' "You said foo..."
;;
"bar")
printf '%b\n' "You said bar..."
;;
"")
;;
*)
printf "%b\n" "${str[*]}:"
printf "%b\n" "Uhhuh..."
;;
esac
fi
done <"$fifoIn" >> "$LogFile" 2>&1 3>"$fifoIn"
echo
したがって、「リーダースクリプト」をインポートしてデーモンとして実行し、ingまたはingを介して会話するか、ビルダーprintf
スクリプトを使用して名前付きパイプにメッセージを送信しますfifoIn
。これは最初からうまくいきましたが、今日は奇妙になりました。
何らかの理由でパイプに書き込むことができる人(または少なくとも書くことができる人のように見える人)を選択的に選択し始めます。エラーは見えませんが、パイプにテキストを送信しようとしましたが、サーバー側では何も起こりません。私はパイプに書き込むためにcronジョブを設定しましたが、問題なく動作し、echo
端末では何も得られません。エラーや権限拒否メッセージもありません。とにかく、クローンの操作は私の端末と同じユーザーに設定されているので、権限の問題ではないようです。
FIFOを削除してサービスを再起動するたびに、通常は一部の端末入力メッセージを受信できるように見えますが、必ずしもそうではありません。 cronが開始したメッセージがサービスジョブに送信された後、ブロックまたは停止されるようです。提供する。もはやパイプを介してメッセージを送信することはできませんが、クローンで始まったメッセージは引き続き正常に流れます!
インターネット検索をしてこのstrace
コマンドを見つけました。私は似たようなことを試してみましたが、strace printf '%b\n' "foo" >> .../path/fifoIn
私はよく理解していない診断システム呼び出しをたくさん受けましたが、そのようなことがなかったので、すべてがうまくいくように見え、最終的に次のようにHey! right here! something broke right here!!
なりました。
...
write(1, "foo\n", 4)
close(1)
...
どうやらいいことだと思います。興味深いのは、メッセージが配信され、デーモンが期待どおりにメッセージを読み取ることです。私はその行を削除し、strace
再びサイコロがありません。
それでは、私よりもio演算とシステムコールについてもっと知っている皆さんにstrace
序文がある時とない時はどうなりますか?読むためにパイプを閉じずに、パイプに通常何が付着しますか?私が言うことを失ったので、あなたが見つけることができる他の手がかりがあるかもしれません。
修正する
@Gilles、私の考えでは、別のプロセスが同じパイプを読み取ろうとして問題を引き起こしていることを示唆しているようです。fifoIn
何らかの理由で関連しているように見えるいくつかのmuttインスタンスを呼び出す新しい関数を作成しました。出力をどのように読み取るかはわかりませんがlsof
、関数を実行した後、次のように読みます(したがってパイプがめちゃくちゃになります)。
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mutt 13874 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 13874 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 13897 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 13897 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 13932 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 13932 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 13971 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 13971 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14012 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14012 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14051 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14051 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14096 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14096 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14124 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
mutt 14124 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
srvc 14298 uname 0r FIFO 8,17 0t0 393222 .../path/fifoIn
srvc 14298 uname 3w FIFO 8,17 0t0 393222 .../path/fifoIn
lsof 15587 uname 1w FIFO 0,8 0t0 176516 pipe
lsof 15587 uname 5w FIFO 0,8 0t0 176524 pipe
lsof 15587 uname 6r FIFO 0,8 0t0 176525 pipe
grep 15588 uname 0r FIFO 0,8 0t0 176516 pipe
lsof 15589 uname 4r FIFO 0,8 0t0 176524 pipe
lsof 15589 uname 7w FIFO 0,8 0t0 176525 pipe
私は誤ってmutt呼び出しを書いたようです(最終的にはサブシェルで実行されます)。コマンドに問題があり、継承されたFDがロックされました。私はそれが答えだと言い、そこからそれを取るでしょう! 「回答」を投稿して喜んでお選びいたします!
答え1
何らかの理由でパイプに書き込むことができる人(または少なくとも書くことができる人のように見える人)を選択的に選択し始めます。エラーは見えませんが、パイプにテキストを送信しようとしましたが、サーバー側では何も起こりません。
以前にプログラムが機能していたが同じプログラムが機能しない場合は、環境が変更されていることを確認してください。
これらの症状は、パイプに複数のリーダーがあり、そのうちの1つだけを観察することと一致します。複数のプロセスがパイプからデータを読み取ると、データがすべてのプロセスに転送される可能性があります。
固定名の名前付きパイプを使用しています。プログラムのどこかにリーダーセクションの無効なインスタンスがある可能性があります。
名前付きパイプが開いているプロセスを確認できますlsof
。
lsof .../path/fifoIn
パイプにライターがないと、open
呼び出し時にリーダーがブロックされる可能性があります。名前付きパイプを開くと、ライターが表示されるまでブロックされます。lsof
パイプがまだ開いていないため、これらの内容は報告されません。open
通話でブロックされたプロセスを見つける方法がわかりません。open
書き込みのために呼び出しを開いて、すべてのプロセスで呼び出しを返すことができます。
sleep 99999999 >.../path/fifoIn &
lsof .../path/fifoIn
開いたファイルは子プロセスによって継承されることを覚えておいてください。パイプが開いている間にプログラムがバックグラウンドで別のプログラムを起動すると、そのプログラムはまだ読み取るためにパイプを開いたままにすることができます。パイプを閉じたいと思うかもしれません。
while … do
subprocess_that_does_not_need_the_pipe </dev/null
done <.../path/fifoIn
または
while … do
subprocess_that_does_not_need_the_pipe 0<&3
done 3<&0 <.../path/fifoIn