#FIFOとは
パイプに名前をつけたものがFIFO。終わってしまった。
ls -l | grep keyword
における | がパイプで、これにファイルシステムグローバルな名前をつけたものがFIFOということになる。性質はパイプと変わらない。上記の例だと
1.grepが起動してパイプのopen(O_RDONLY)でブロッキング
2.lsがパイプをopen(O_WRONLY)で開き
3.lsが出力をパイプにwrite()
4.grepのブロックが解除され、入力をread()
5.lsがパイプをclose()
6.grepがパイプをclose()
みたいな動きになる。
open()でブロッキングするのであってread()やwrite()ではブロッキングしない。
O_RDONLYではopen()でブロック
O_RDWRではread()でブロック
という挙動になる。
こんなのどこに書いてあるんだ?
これは日本語man pagesに書いてあるのだがわかりづらい。つまりこうだ。
seekのきかないファイル(パイプやFIFO)は現在位置から読み込みを開始して、データがない場合はEOFとみなして0を返す。
EOFを返すのはO_RDONLYでのopenが成功した(有効なfdが返された)場合、かつFIFOにデータがない場合だけである。
ゆえにread()ではブロッキングしない。**openモード次第でブロックの挙動が変わる。上記参照。**通常はこれで困ることはないが、プロセス間通信でスレッドを立てて、ループでデータの到着を待つような処理をする場合、open()でブロッキングしてCPUの浪費を防ぐ必要がある。しかし人情として、いちいちループ中でopen()/close()はしたくない。read()でブロッキングが可能ならそれがベストだ。
些細な問題を除いてreadでもブロッキングはできるのだが、mqで解決したのでそれはまあ良しとしよう。
#そこでメッセージキュー
POSIXメッセージキューは固定サイズのメッセージを有限個格納できるキューである。作成時にブロッキング属性を付与するため、キューの受信を実行しても(ブロッキングキューであれば)メッセージ到着までブロッキングしてくれる。
なのでスレッドのループ中でメッセージの到着を待つような処理に向いている。パイプのようにSIGPIPEを発生することもなければ、FIFOの両端が閉じるとデータを失うようなこともない(カーネル寿命なのでシャットダウンまでデータを保持してくれる)。
#プロセス間のデータ交換
プロセス間通信の方法は、ほかにもセマフォやシグナル、共有メモリなどがあるそうなのだが、データ交換を目的に行う場合はFIFOかキューかドメインソケットになると思う。それぞれ一長一短はあると思うのでいずれまとめてみたい。
#で、些細な問題って何?
googleでman fifoとかで検索するとヒットするのだが、
FIFOに対してO_RDWR指定でopenした場合の動作は未定義である。readでブロッキングできる代償は未定義動作だ。
まあ承知の上で使うならいいのではないだろうか。個人的にはこういう逃げ口上のようなマニュアルは大嫌いだが。