SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

ファイルディスクリプタについて

ファイルディスクリプタについて(5)
~多重I/O「Multiplex I/O」の種類の特徴、使い方

第5回

epoll

 上記サンプルのように、管理対象のディスクリプタが2個と少ない場合、かつ動的に増えたり減ったりしない場合はselect(2)poll(2)の使用で結構でしょう。しかしソケットディスクリプタを使用するなど、大量かつ動的にディスクリプタが増減するような場合、select(2)poll(2)では性能上の問題があると言われています。

 上記の通り、select(2)は管理可能なディスクリプタ数に上限がありますが、それ以外にも、select(2)poll(2)は、ready状態になったディスクリプタが一つでも存在した時、全ディスクリプタを対象に走査する必要があります。加えて作り上の問題で内部で作成しているディスクリプタ管理テーブルの作成と破棄を繰り返すことで処理が重くなるからだそうです(注4)。

 上記のような問題を解決するためにはepoll(7)を利用します。epoll(7)では管理するディスクリプタにデータが届くと、操作対象のディスクリプタのみ返されるので、処理すべきディスクリプタだけを処理でき、無駄なサーチがなくなります。

epoll_sample.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/wait.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <sys/param.h>

void sigchld_ign( );
int  timerfd( );
void child_process( int efd, int child_cnt );

int main(int argc, char ** argv ) {
    struct epoll_event ev, evs[2];
    uint64_t   read_cnt;
    int        epfd, nfds, efd, tfd, i;
    pid_t      pid;

    if( argc < 2 ) {
        fprintf( stderr, "Usage: %s <num>\n", argv[0] );
        exit( EXIT_FAILURE );
    }
    sigchld_ign( );
    efd = eventfd( 0, 0 );
    tfd = timerfd( );
    if(( pid = fork( )) == 0 ) {
        child_process( efd, atoi( argv[1] ));
    }
    printf( "Parent read to efd. pid:[%d] ppid:[%d]\n", getpid(), getppid());

    epfd = epoll_create( 2 );
    ev.data.fd = efd;
    ev.events  = EPOLLIN;
    epoll_ctl( epfd, EPOLL_CTL_ADD, efd, &ev );
    ev.data.fd = tfd;
    ev.events  = EPOLLIN;
    epoll_ctl( epfd, EPOLL_CTL_ADD, tfd, &ev );
    while( 1 ) {
        nfds = epoll_wait( epfd, evs, 2, 1000 );
        if( nfds == 0 ) {
            kill( -pid, 0 );
            if( errno == ESRCH ) {
                break;
            }
            continue;
        }
        for( i = 0; i < nfds; i ++ ) {
            if( evs[i].data.fd == efd ) {
                read( efd, &read_cnt, sizeof( uint64_t ));
                printf( "eventfd Parent read:[%ld]\n", read_cnt );
            }
            if( evs[i].data.fd == tfd ) {
                read( tfd, &read_cnt, sizeof( uint64_t ));
                printf( "timerfd Parent read:[%ld]\n", read_cnt );
            }
        }
    }
    printf( "Parent completed read loop\n" );
    return( 0 );
}
・・・(以降は、select プログラムと同じ)
注4

 この件は少し前にC10K問題として取り上げられており、そこでもselect(2)のディスクリプタ管理数の限界、およびpoll(2)の遅延について論じられています。

次のページ
レベルトリガ機能とエッジトリガ機能

この記事は参考になりましたか?

ファイルディスクリプタについて連載記事一覧

もっと読む

この記事の著者

赤松 エイト(エイト)

(株)DTSに勤てます。WebアプリやJavaやLL等の上位アプリ環境を密かに憧れつつも、ず~っとLinuxとかHP-UXばかり、ここ数年はカーネル以上アプリ未満のあたりを行ったり来たりしています。mixiもやってまして、こちらは子育てとか日々の日記メインです。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4816 2010/02/26 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー