mkfifo のあまり書かれていない特徴2012年08月17日 15時32分21秒

mkfifo は UNIX のシステムコールであり、UNIX コマンドの一つでもある。FIFO は First-In First-Out で先入れ先出し。データ構造などでは Queue、キューと呼ばれる。UNIX 上では名前付き pipe などとも言われる。

mkfifo でファイルを作成。tail で読み出す。


term1 % mkfifo /tmp/fifo
term1 % tail -f /tmp/fifo

もう一つのターミナルで入力する。

term2 % echo 1 > /tmp/fifo
term2 % echo 2 > /tmp/fifo

そうすると先程の tail が出力をだす。

term1 % mkfifo /tmp/fifo
term1 % tail -f /tmp/fifo
1
2
^C

fifo には幾つかの特徴がある。

まず、open が書き込み側と読み出し側が open を呼ぶまでブロックされる。echo と tail ではなく、両方で cat を使うとその動作が良く解る。読み出し cat を先に起動しても、書き込み cat が始まるまで、待ち続ける。逆もまた然り。

そして、fifo は何度でも使い直す事ができる。cat の実験は同じfifo を用いて何度でもできる。

また、出力側が close をすると、read は 0 を返すことになる。そのため、cat はすぐに終了。select 等や再 open 等で、読み出しの状態を調べる tail -f は、読み出し続ける事になる。

最後に、書き込み側も読み出し側も複数が行なえる。複数のプロセスでの読み出しは、各入力は一つのプロセスにしか渡らない。しかし、close は全てに伝達されてしまうので、一気に全てのプロセスの read が 0 を返す。ほとんど、使い様の無い形だろう。複数の書き込みプロセスが各々書き込んで、一つのプロセスで処理は利用できる。書き込んだ順番と内容は保護されるが、内容は行単位で独立していないと処理しづらい。

この性質を利用して、大量の圧縮ファイルを復元せずに、同時に伸長しつつ、全てを一気にに grep 等といった使い方ができる。


% sh -c 'for i in /var/log/messages*bz2; do bzip2 -d -c $i > /tmp/fifo & done'
% grep da /tmp/fifo
Aug 17 01:09:25 kernel: da0 at umass-sim0 bus 0 scbus0 target 0 lun 0
Aug 17 01:09:25 kernel: da0: <IC25N040 ATCS05-0 0811> Fixed Direct Access SCSI-0 device 
Aug 17 01:09:25 kernel: da0: 40.000MB/s transfers
Aug 17 01:09:25 kernel: da0: 38154MB (78140160 512 byte sectors: 255H 63S/T 4864C)

まあ、伸長したので正しく改行が行なわれているとは限らないが、あくまで使い方の一例として。