はじめに
前回は、ファイルディスクリプタの概要について解説しました。今回は、新たに追加された3個のファイルディスクリプタの中から、イベント用ファイルディスクリプタ「eventfd」を取り上げ、使用法や特徴、既存のファイルディスクリプタとの違いについて、説明していきたいと思います。
連載概要
この連載は、次のような内容について述べていく予定です。
連載目次
- 第1回:ファイルディスクリプタの概要
- 第2回:イベント用ディスクリプタ「eventfd」の特徴
- 第3回:タイマー用ディスクリプタ「timerfd」の特徴
- 第4回:シグナル用ディスクリプタ「signalfd」の特徴
- 第5回:多重I/O「Multiplex I/O」の種類の特徴、使い方
- 第6回:多重I/Oの性能とC10K問題
- 第7回:シグナル駆動I/Oの特徴、使い方
- 第8回:非同期I/O「Asynchronous I/O」の使い方と性能差
- 第9回:ファイルディスクリプタパッシングの特徴、使い方
サンプルプログラムは100行前後程度までは画面に記載します。全プログラムは圧縮してページ上部よりダウンロード可能にしています。make
コマンドでコンパイルできます。i386/x86_64環境で動作確認済みです。
プログラムのボリューム上、エラー処理や引数チェックなどを省いているので、あらかじめご了解ください。また使用法を誤るとシステムに重大な影響を与える可能性があります。利用する場合は責任のとれる環境において実行するよう、お願いします。
当トピックでは、実際にプログラムを通して動作確認や性能測定を行うことで、個人的な見解を述べさせていただきます。あくまで個人的な感想に基づいているので、反論や指摘などあるかと思います。指摘や質問などは大歓迎なので、その際はぜひご連絡ください。可能な限りの対応に努めます。
eventfdについて
eventfd(2)
は、あるアプリケーションが他のアプリケーションに対して通知したり、逆に通知を待つことができるディスクリプタです。通知できる情報は8バイトの整数値のみで、同一ディスクリプタを持つ全ての親子プロセスおよびスレッドで使用可能です。関数は下記のとおりです。詳細はリファレンスを参照ください。
int eventfd( unsigned int initval, int flags )
- EFD_NONBLOCK
- EFD_CLOEXEC
戻り値がファイルディスクリプタとなり、initval
で指定した値で初期化されます。通常は0を設定します。flags
には、以下の値を論理和で指定することで、eventfd(2)
の振舞いを変更します。
対象ディスクリプタをノンブロッキング設定にするフラグです。イベントが届かない間、ファイルディスクリプタをreadしている時は待ち状態になってサスペンドしますが、当オプションが指定されるとサスペンドせずにEAGAINを返して待ち状態から解除されます。
子プロセスを生成、そこでexecveでプログラムが起動された際、親プロセスで開いていたファイルディスクリプタが自動的に閉じられます。
サンプル
前ページの関数を使ったサンプルが下記です。
#include <sys/eventfd.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> int main(int argc, char ** argv ) { int efd, j; uint64_t u; if( argc < 3 ) { fprintf( stderr, "Usage: %s <num> <num> ...\n", argv[0] ); exit( EXIT_FAILURE ); } efd = eventfd( 0, 0 ); switch( fork()) { case 0: for( j = 2; j < argc; j ++ ) { u = strtoull( argv[j], 0, 0 ); write( efd, &u, sizeof( u )); } close( efd ); printf( "Child completed\n" ); exit( EXIT_SUCCESS ); default: printf( "Parent sleep %d sec.\n", atoi( argv[1] )); sleep( atoi( argv[1] )); read( efd, &u, sizeof( uint64_t )); printf( "Parent read by eventfd:[%llu]\n", ( unsigned long long )u ); close( efd ); exit( EXIT_SUCCESS ); } }
上記プログラムは、eventfd(2)
によって生成されたファイルディスクリプタに対し、子プロセスが数値を書き込み、親プロセスがそれを読みだす構成になっています。親プロセスはread(2)
にて読み出せるまでサスペンドします。子プロセスは数値を書き込むと、親プロセスはread(2)
でのサスペンドが解除され、書き込まれた値を読み出します。