特徴
以上の動作より、eventfd(2)によるファイルディスクリプタの特徴は下記と思われます。
- 複数回書き込まれても、読み込みは1回しか行わず、取得した値は書き込んだ値の合計値になっています。
- 読み込み回数が少ないことから、類似機能に比べて性能は良いです。
- ファイルディスクリプタをクローズしても、他のプロセスに対してEOFが届きません。
一方からファイルディスクリプタがクローズされ、他方でそのファイルディスクリプタをread(2)すると、0バイト長読み込みが行われます。
いわゆるEOF(End Of File)のことで、ファイルディスクリプタがクローズされたことを検知する際に使用します
以下は、名前なしpipeとsocketpair(2)両方ともに当てはまる特徴です。
- 複数回書き込まれた後で読み込むと、書き込まれた回数分読み込みます。
- 複数回読み込まれる為、1回の読み込みで全て取得する
eventfd(2)に比べると性能は劣ります。 - 一方からファイルディスクリプタをクローズすると、他方に対してEOFが届きます。
上記の特徴を鑑みると、eventfd(2)は複数プロセスで共有して使用する仕様で、名前なしpipeおよびsoketpair(2)は2個のプロセス間での使用が推奨される仕様と思われます。
pipe(2)やsocketpair(2)でも複数プロセスで使用することは可能です。
加えてeventfd(2)は、ファイルディスクリプタを1個しか生成しません(pipe(2)やsocketpair(2)では2個生成しています)。このことは、アプリケーション側にはそれほど利点がある訳ではないですが、カーネル側のオーバーヘッドの違いが大きいようです(バッファリングも8バイトで済みますし、異なるディスクリプタを経由する必要もないからでしょう)。
また、ディスクリプタのクローズ時にEOFが届かないことも大きな違いです。通常、ディスクリプタを監視する際、ディスクリプタを読み込んでEOF(read(2)の戻り値が0バイト)が返ることでディスクリプタが閉じられたことを判定します。しかしeventfd(2)はそれができません。他のプロセスにて全てディスクリプタが停止したことを検知したい場合、どのように判定するかを考える必要があります。
まとめ
eventfd(2)は、既存のpipe(2)やsocketpair(2)と似ていますが、EOFを読み込めないなど、扱いが難しい所も含んでいます。名前なしpipeやsoketpair(2)に置き換える際は、多重I/Oを使用していない、かつイベントトリガとしてしか使用していない状況ならば可能と思いますが、置き換える際のテスト工程を考えると、それほどのメリットも感じないのが本音です。
また、複数回の書き込みをいっぺんに読み込むので性能は良いでしょうが、書き込まれた値に意味を持たせている場合、読み込んだ値をマスクして処理分岐するなどの処理が必要になります。今後の使用の際は、そのあたりを勘案して利用するのが良いでしょう。
次回は、設定された時間が経過すると、ファイルディスクリプタ経由で満了したことを通知できるディスクリプタ「timerfd」について説明します。
