SHOEISHA iD

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

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

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

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

ファイルディスクリプタについて(3)
~タイマー用ディスクリプタ「timerfd」の特徴

第3回

pipe(2)との併用

 前述した、timer_create(2)pipe(2)を併用することで、timerfd(2)とほぼ同一の機能を実装できます。シグナルハンドラもしくはコールバック関数内でpipe(2)write(2)し、メインプロセスでは多重I/O等でpipe(2)read(2)を待ちます。タイマー発生時、pipeを経由してメインプロセスが検知し、しかるべき処理を行う、という流れです。

 以下のサンプルソースはスレッド版、多重I/Oはselect(2)で実装しました。もちろんシグナル版でも実装可能です。

timer_create_by_pipe.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <wait.h>
int pipefd[2];
#define TV2SEC(tv) ((double)((tv).tv_sec) + (double)((tv).tv_usec / 1000000.0))
void timer_thread( sigval_t val );

int main( int argc, char ** argv ) {

    if( argc < 2 ) {
	exit( 1 );
    }
    int max_cnt = atoi( argv[1] );

    struct timeval  tv1,tv2;
    sigval_t sig;
    int      i;
    timer_t timer_id;
    struct sigevent ev;
    ev.sigev_notify             = SIGEV_THREAD;
    ev.sigev_value.sival_ptr    = &timer_id;
    ev.sigev_notify_function    = timer_thread;
    ev.sigev_notify_attributes  = 0;

    struct itimerspec ts;
    ts.it_value.tv_sec = 1;
    ts.it_value.tv_nsec = 0;
    ts.it_interval.tv_sec = 1;
    ts.it_interval.tv_nsec = 0;

    pipe( pipefd );
    timer_create( CLOCK_MONOTONIC, &ev, &timer_id );
    timer_settime( timer_id, 0, &ts, 0 );

    fd_set rset, org_rset;
    FD_ZERO( &org_rset );
    FD_SET( pipefd[0], &org_rset );

    for( i = 0; i < max_cnt; i ++ ) {
	rset = org_rset;
	int rtn = select( FD_SETSIZE, &rset, 0, 0, 0 );
	if( rtn < 0 && errno == EINTR ) {
	    continue;
	}
	read( pipefd[0], &sig, sizeof( sigval_t ));
	gettimeofday( &tv2, 0 );
	if( i ) {
	    printf( "timer_thread %d Path... [%f]\n",
		i, TV2SEC( tv2 ) - TV2SEC( tv1 ));
	}
	tv1 = tv2;
    }
    return 0;
}

void timer_thread( sigval_t val ) {
    write( pipefd[1], &val, sizeof( sigval_t ));
}

まとめ

 timerfd(2)は、既存機能であるteimer_create(2)に勝るとも劣らない、非常に利用価値の高い機能だと思います。

 timer_create(2)ではコールバック関数が非同期で呼び出されますが、timerfd(2)はコールバック関数を用意する必要がなく、ファイルディスクリプタを複数管理したり、非同期で監視することも容易です。コールバック関数内では複雑な処理をするには制限もありますが、ファイルディスクリプタで管理する場合はその制限も外れます。

 代替案で提示した pipe(2) を利用する案でも十分運用は可能と思われますが、pipe用変数のスコープがグローバルになることから、管理が煩雑になりがちで、この点を踏まえても timerfd(2) は高い有用性を備えていると考えています。

 定期間隔で処理を行う際、有効に利用できる機能でしょう。

 次回は、プログラムの内外部から発行されたシグナルイベントを補足し、通知するためのシグナル用ディスクリプタ「signalfd」について説明します。

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

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
ファイルディスクリプタについて連載記事一覧

もっと読む

この記事の著者

赤松 エイト(エイト)

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

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

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

この記事をシェア

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

イベント

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

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

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

メールバックナンバー