名前付きパイプ:いくつかの実験によって混乱が発生する

名前付きパイプ:いくつかの実験によって混乱が発生する

いろいろな記事や質問を読んでいますが、毎日使用している内容がまだ混乱していて、それがどれほど混乱しているのか、全く気付いていませんでした。私はLinuxで(名前付き)パイプを試しています。

初めて 試みは簡単です。パイプバッファがどのように機能するかをご覧ください。

#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
ctrl+c
#3
cat /tmp/mypipe

観察するecho:データを読み取る前に終了すると、catパイプには何も書き込まれません(cat実行され続けますが、パイプから何も読み込まれません)。を入力しproducent >named_pipeて終了すると、producentパイプバッファのサイズに一致するデータの一部が書き込まれ、named_pipe読み込まれるまでここに残っていると仮定しますconsument(これはうまくいきません)。だから私が次にしたことは次のとおりです。

2位consumentパイプのもう一方の端に接続してみてください。

#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
#3
cat /tmp/mypipe

観察する:コマンドはメッセージをcat表示し、両方のプロセスが終了します。"Hello World"ここで興味深いのは、手順2ではps -elfコマンドが表示されないことですechoecho誰かがパイプからデータを読み取るのを待っているようです。これが最初の試みでパイプに何も印刷されない理由です。

3番目の場所 パイプコマンドが「永久に」実行され、パイプに書き続け、何が起こるかを見てください。

#1
mkfifo /tmp/mypipe
#2
yes >/tmp/mypipe
#3
cat /tmp/mypipe

観察する:これは期待どおりに機能し、パイプに渡された内容をcat印刷します。しかし、代替をyes試してみました。これにより、コマンドが終了するまで何も印刷されません。cattail -ftailyes

4位 努力するのが最大の謎です。

# 1#
mkfifo /tmp/mypipe

# 2#
for i in $(seq 1 10000); do echo -n $i"|"> /tmp/mypipe; done

# 3#
for i in $(seq 1 10); do echo "${i}# Read:"; cat /tmp/mypipe && echo ""; done

その後、3#コマンドは同様の内容を入力し始めます。

1# Read:
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|
2# Read:
109|
3# Read:
110|
4# Read:
111|
5# Read:
112|
6# Read:
113|114|115|
7# Read:
116|
8# Read:
117|
9# Read:
118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255|256|257|258|259|260|261|262|263|264|265|266|267|268|269|270|271|272|273|274|275|276|277|278|279|280|281|282|283|284|285|286|287|288|289|290|291|292|293|294|295|
10# Read:
296|297|298|299|300|301|302|303|304|305|306|307|308|309|310|311|312|313|314|315|316|317|318|319|320|321|322|323|324|325|326|327|328|329|

質問:

最初と2番目の試み:

  1. この特別な場合、名前付きパイプは|bashで知られている古典的なパイプと同じですか?
  2. 生産者は常に消費者を待っていますか?それでは、パイプバッファの目的は何ですか?このような行為を通信遮断といいますか?
  3. Linuxは、消費者がパイプに接続して通信できる時期をどのように知ることができますか?試してみましたが、lsof named_pipe情報は提供されません。この情報はどこに保存されていますか?また、次のことを試しましたが、結果はcatパイプから読み取れないことです。

    #1
    mkfifo /tmp/mypipe
    #2
    echo 1 >/tmp/mypipe
    #3
    rm /tmp/mypipe
    #4
    mkfifo /tmp/mypipe
    #5
    cat /tmp/mypipe
    
  4. 入力中:producent >/tmp/mypipe 入力と同じcommand |誰かがあるコマンドを別のコマンドにパイプしたいのですが、パイプの後に別のコマンドを入力するのを忘れてしまったことを意味します(psこの場合は最初に表示せずcommand)。

3回目の試み:

  1. cat違いは何ですか?tail -f

4回目の試み:

  1. ここで何が起こっているのでしょうか?データブロックサイズの読み取りが不正確な理由は何ですか?私は出力が次のようになると期待しています:

    1# 読み: 1| 2# 読み取り: 2|3# 読み取り: 3|

PS:他の起動コマンドシーケンス(最初に読み込んだ後に書き込む)も試しましたが、結果は同じです。

PPS:これは明確であることを願っていますが、生産者=パイプに書くプロセスです。コンシューマ = パイプからデータを読み取るプロセスです。

主にCスクリプトの知識が少ない人にこの内容を説明できますか?とても感謝しています。

編集者の回答:Joe Sewell

  1. 削除確認
  2. 2.

私が知っている限り、両方とも並列に実行されます。つまり、次の2つは同じではありません。

find | less

そして

find > /tmp/file && less /tmp/file

次のコマンドを実行すると、HDDが機能せず、lessコマンドに表示されるデータが十分になるまで停止するように見えることがさらに観察されました。

find | less

shifg+g(ファイルの末尾に移動)をクリックすると、lessハードドライブはすぐに動作を開始し、データの出力を開始します。これはless、コマンドに表示するのに十分なデータがあるときにfindデータを生成しないように指示することを意味しますか?これを同期といいますか?パイプに書き込まれたデータの転送量はバッファサイズと一致しますか?また、クリックしてfindステータス(ps aux-stat列)が変更されたことを確認しました。S+ to D+shift+gless

S    interruptible sleep (waiting for an event to complete)
D    uninterruptible sleep (usually IO)
+    is in the foreground process group.

┌─[wakatana@~] [63 files, 178Mb]
└──> ps aux | egrep -w 'less|find'
wakatana     6071  0.0  0.0  12736  1088 pts/5    S+   23:15   0:00 find
wakatana     6072  0.0  0.0   7940   928 pts/5    S+   23:15   0:00 less
wakatana     6183  0.0  0.0   7832   892 pts/6    S+   23:20   0:00 egrep --color=auto -w less|find
┌─[wakatana@~] [63 files, 178Mb]
└──> ps aux | egrep -w 'less|find'
wakatana     6071  0.0  0.0  12808  1304 pts/5    D+   23:15   0:00 find
wakatana     6072  0.0  0.0   9556  2508 pts/5    S+   23:15   0:00 less
wakatana     6193  0.0  0.0   7832   892 pts/6    S+   23:21   0:00 egrep --color=auto -w less|find
  • 誰がこの信号を生産者に送りますか?それでは、消費者は自分がすでに製品があるパイプライン(私のrmパイプラインの例のように)に接続されていることをどうやって知ることができますか?

  • 削除確認

  • 削除確認

  • 私は新しい行が私を混乱させるとは思わない。以前に観察した内容(そしてあなたの確認:「はい、両端はお互いを待ちます」)に基づいています。私はこれを期待しています:

  • I. 最初のループの最初の繰り返しはパイプに書き込まれ、誰も読みませんので、ここで待ちます。

  • 2. 2 番目のループが実行されると、最初の反復で最初のループによって書き込まれたデータが読み込まれ、ここには何も書き込まれなくなり、読み取れなくなります。

  • 三。 2番目のループは、最初のループが次のデータを書き込むのを待つか(順序は重要ではないため)、最初のループは2番目のループが書き込んだデータを読み取るのを待ちます。

したがって、1 回の書き込みが 1 回の読み取りに対応すると予想されます。また、ループが実行されていないことを確認していたので、コンシューマがコンテンツを読み取らなくても何も印刷されない場合でも、STDOUTに何かを印刷するかどうかを確認するために元のコマンドのいくつかを修正しました。

for i in $(seq 1 10000); do
  if [ $(( $i % 5 )) -eq 0 ]; then
    echo $i;
  else
    echo -n $i"|"> /tmp/mypipe;
  fi;
done

「作成プロセスでは改行文字がまったく送信されないので、読者は「十分」という言葉を聞くまで読んでください。」

  • 誰が消費者に十分だと言うのでしょうか?

「最初のケースでは、fifoのバッファがいっぱいになる可能性があります」

  • 上記のように通信がブロックされている場合は、バッファをどのように入力しますか?

「それで読者に駆けつけました」

  • どういう意味ですか?申し訳ありません。私の英語力が悪いです。

「通信を非同期化する方法があるが…」

  • この場合、非同期と同期の違いが何であるかを簡単に説明できますか?

ベストアンサー1

質問リストに番号で回答するには、次の手順に従ってください。

  1. fifoとも呼ばれる名前付きパイプは、デフォルトでシェルによって生成された名前付きパイプと同じです。主な違いは、2つの端の間のシェルバージョンの同期が直感的ですが、使用されているように見える名前付きパイプには、シェルが実行する操作についての知識が必要であることです。

  2. はい、両側はお互いを待っています。 fifoの目的は、あるプロセスの出力を別のプロセスの入力に渡すシェルパイプの目的と同じです。彼らいいえ一時ファイル。私はこれがあなたが混乱している場所だと思います。このようなシェルコマンドの場合cat somefile.txt | less両方コマンドはフォークされたプロセスとして同時に実行され、パイプは両方のプロセスを同期させるために使用されます。私の記憶が正しければCで修正すればい​​いのですが、シェルコマンドを使うとそれほど簡単ではありません。

  3. プロセスはパイプのもう一方の端が接続されたときに信号を受け取ることができますが、上記のように、全体的な意図は通常、2つのプロセスを同期状態に保つことです。作成者は何かを送信し、書き込み操作が完了したことを知って続行できます。

  4. bashそしてtcshそれはあなたが「忘れる」ことを許可しません。コマンドは実行されません。

  5. tail -fstdin何でも表示するには、EOFを取得するまで(この場合)ストリーム全体を読み取る必要があります。あなたの実験ではエンディングは発生しませんでした。cat一方、入力処理はすぐに開始できます。

  6. 書き込みプロセスでは改行文字がまったく送信されないため、読者は「十分」という言葉を聞くまで読むだけです。最初のケースでは、fifoのバッファがいっぱいになり、リーダにフラッシュされることがあります。後続の出力は似ている可能性があり、システムタイミングによって異なります。

ここで別の混乱した問題に対処します。シェルはリダイレクトを処理します。今後コマンドを実行します。これは、FIFOのもう一方の端が接続されるのを待っているcatため、プロセスリストに表示されないことを意味します。bash今後ランニングcatまたは作家に関連するすべて。同様に、ライターが接続されるまで読み取りコマンドは実行されません。

私の考えでは、あなたの最大の誤解は名前付きパイプですいいえ一時ファイル。名前のない通路でもありません。通信を非同期にする方法がありますが、次から実際の一時ファイルを作成する方が/tmp良いと思います。する両方のプロセスを同時に実行したいです。

おすすめ記事