FIFO Special File
前置き
元々は[ffmpeg: 任意の画像加工コマンドで動画を加工する]内の文書だったが、長くなったので分けたもの。
基本動作
データが first-in first-out する特殊ファイル, named pipe
とも呼ばれる。以降fifo
と表記。
cat example.txt | more
の|
vertical-lineによるパイプよりも複雑なことをするための道具の一つ。
fifo(7)
bash(1)/SHELL GRAMMAR/pipeline
open(2)/NOTES/FIFOs
fifo
に対して書き込み側が"abc…"
と書き込むと、読み込み側に"abc…"
と出て来るイメージ。
だからパイプと比喩される。しかし、fifo
はパイプそのものではない。
上記動作をするものがパイプ。
一方でパイプ関係を成立させるためのパスがfifoファイル
。
fifoファイル
自体はすなわちでパイプではない。後述のパイプの終了に関する仕様が理由。
fifoファイル
はファイルシステム上にパスを持つが、データがストレージに保存されるわけではない。
見掛け上のファイルサイズは常に0 Byte
。
利用する上で注意しなければいけないことはブロッキングとパイプの終了。
ブロッキング
fifo
では読み込み側と書き込み側の両方がopen
操作をするまで、つまり両者が揃うまで、それぞれのopen
は終わらない。
このことを指して「(条件が揃うまで)ブロックされる」や「(条件が揃うまで)制御は戻らない」などと呼ぶ。
ブロッキングはbash
でfifo
を扱う場合にも関係する。
次のbash
表現はブロッキングが起きる可能性がある。
exec 110< "fifoA"
# fifoAをread-modeでopenして、110番のfile descriptorで管理するという意味
open
の操作がある。そのため、別のプロセスがパイプのもう一方として"fifoA"
をwrite-mode
でopen
するまで上記exec
は終わらない(制御は戻らない)。
bash
のリダイレクト操作構文については別ページ[bashのFD(file descriptor)操作について]へ。
このブロッキングには例外(それと少し予測しにくい挙動)がある
O_NONBLOCK
を指定してopen
した場合はブロックされない。。
rw-mode
(read and write mode)でのopen
の際はブロックされない。
bash
ではO_NONBLOCK
指定はできないため、関係がない。
bash
では<>
less-than-sign,greater-than-signでrw-mode
によるopen
が出来る。
パイプの終了
読み込み側がclose
した時点で、書き込み側のwrite
は失敗するようになる。
書き込み側がclose
して、なおかつ読み込み側が残り全てをread
したらEOF
end-of-fileにより終了する。
一度close
して、再び同じfifoファイル
を開いても同じパイプには繋がらないため、読み込み側は続きのデータが欲しい間はclose
してはいけない。
(この説明は正確ではない。再open
でも同じパイプから続きのデータを読める状況は存在する。下記参照)
余談, パイプの終了, 複数の書き込み側, 複数の読み込み側
別ページ [ffmpeg: 任意の画像加工コマンドで動画を加工する] の余談と、複数の書き込み側と複数の読み込み側がある場合のfifo-pipe
の挙動の説明をする。
exec 121> "${fifo_s2_to_s3}"
など、リンク先の実装例ではブロッキングを考慮したために書き方が複雑化した。<>
を使えばシンプルに表現出来たかも知れない。
さらに言えばfifo
は複数の書き込み側
と複数の読み込み側
という組み合わせをサポートしている。
この仕様を使った場合も、コードがシンプルになったかも知れない。
複数の書き込み側
複数の書き込み側
によって並列して書き込まれたデータは直列に並び変えられて読み込み側に届く。
この挙動は通常ファイルに並列に書き込んだ際の結果と異なる。
複数の読み込み側
複数の読み込み側
がある場合にそれぞれの読み込み側に来るデータはどうなっているか?
想定できる次の二つの動作のうち、正解は後者である。
-
[誤]: 全ての読み込み側に同じデータが来る
-
[正]: 製造ライン作業のように手が空いた読み込み側が先頭から取っていく。
読み込み側も書き込み側と同じ様に直列に読み込んでいく仕様である。
複数の読み書きがある際のパイプの終了
挙動を予測しにくいのがパイプの終了に関するこの仕様。
一つ以上の書き込み側がopen
中ならば書き込みは継続しているとパイプに見なされる。
一つ以上の読み込み側がopen
中ならば読み込みは継続しているとパイプに見なされる。
つまり、書き込み側も読み込み側も同役割のfile descriptor
が一つ以上存在してさえいれば、一旦close
してから再びopen
しても、同じパイプに対して書き込みや読み込みを再開することが出来る。
このパイプの終了を回避出来る仕様を使えばbash
の並列実行でfifo
をopen
だけして1byte
も読み込まない、読み込み意思表示キーパーを置いておけば、[ffmpeg: 任意の画像加工コマンドで動画を加工する]でFD操作
なしで書けたかも知れない。
その場合はきっと、いささか乱暴なジョブコントロールが必要になっただろうが。