ファイヤープロジェクト
fifo
2003-07-20T15:13+09:00   matsu
FIFOは名前付きパイプらしい.パイプがファイルで嬉しくなる.
man 4 fifoによると,FIFOとは先入先出特殊ファイル,名前付きパイプで,パイプとことなる点は,ファイルシステムに関連付けられていることである.popen関数やpipe関数でファイルストリームやファイルディスクリプタを取得できたことから考えて,この機構があるのは予想通りで期待通りだろうか.FIFOはコマンドラインでも堪能(?)できる.
mkfifo hoge
cat < hoge &
echo "hogefugafoo"
などとする.このときls -lとすると
prw-r--r--    1 foo    foo           0  4月 13 01:53 hoge
と最初の文字がパイプのpになっている.以下,FIFOについてまとめてみた(man 4 fifoをまとめただけ).
  • いくつかのプロセスによってオープンされている一つのFIFOについて一つのパイプが管理される.
  • FIFOにデータが渡されるときは,読み出しと書き込みの両方(パイプの両端)がオープンされている必要がある.
  • 通常はFIFOをオープンすると,もう一端がオープンされるまでブロックされる.
  • ノンブロッキングモードでFIFOをオープンしたときの動作は以下のようになる.
    書き込み側がオープンされていない状態で読み込み専用でオープンした場合.
    成功.
    読み込み側がオープンされていない状態で書き込み専用でオープンした場合.
    失敗(ENXIO).さらにオープンしようとしたそのプロセスにSIGPIPEが送られる.
  • 読み書き両用でオープンした場合,Linuxではブロッキングモード,ノンブロッキングモードともに成功する(これはPOSIXでは定義されていない).
先にコマンドラインからmkfifoでFIFOを作成した.他にも
mknod hoge p
で作成することができる.CでのFIFOの作成する方法にも両者に対応する同名の関数mkfifoとmknodがある.mknodの方が移植性が高いらしいが,man mknodによるとFIFOはmkfifoで作成すべきとある.以下にmkfifoとmknodそれぞれでFIFOを作成するサンプルを示す.
FIFOを使用するサンプルを作ってみた.まずはFIFOから読み込むサンプルfifo-reader.
そしてFIFOに書き込むサンプルfifo-writer.
そして実行.
fifo-reader
としておいて,別のコンソールで
fifo-writer
などとする.ある時間内であれば,同時にfifo-writerを複数起動して一つのfifo-readerに読ませることができる.
for A in $(seq 1 10); do fifo-writer & done
複数のfifo-writerを起動しても正確にfifo-readerが動作するための注意は,「一回でreadするサイズは,後者で一回でwriteするサイズにそろえる」ことである.サンプルではこれらは
#define BUF_SIZE PIPE_BUF
で設定できるが,両者のBUF_SIZEの値が異なると,予期しない結果になったりする.例えば上記のサンプルのfifo-readerの出力は
make /tmp/fifo-sample
8198 received 4096 bytes:       My pid = 8200.
8198 received 4096 bytes:       My pid = 8204.
8198 received 4096 bytes:       My pid = 8205.
8198 received 4096 bytes:       My pid = 8206.
8198 received 4096 bytes:       My pid = 8202.
8198 received 4096 bytes:       My pid = 8203.
8198 received 4096 bytes:       My pid = 8201.
8198 received 4096 bytes:       My pid = 8209.
8198 received 4096 bytes:       My pid = 8207.
8198 received 4096 bytes:       My pid = 8208.
8198 received 0 bytes:  
となる.これはfifo-writerを
for A in $(seq 1 10); do  ./fifo-writer &  done
とした結果である.これをfifo-readerで
#define BUF_SIZE (PIPE_BUF*2)
などとすると,fifo-readerの出力は
8237 received 8192 bytes:       My pid = 8239.
8237 received 8192 bytes:       My pid = 8243.
8237 received 8192 bytes:       My pid = 8244.
8237 received 8192 bytes:       My pid = 8246.
8237 received 8192 bytes:       My pid = 8247.
8237 received 0 bytes:  
と期待しない結果になってしまう(10のfifo-writerでFIFOに書き込んだのに5個分しか出力がない).
matsu(C)
Since 2002
Mail to matsu