libuvに関する覚書(1) : タイマー uv_timer_t

関連する投稿
libuvに関する覚書(2) : ファイル監視 uv_fs_event_t
libuvに関する覚書(3) : パイプ uv_pipe_t
libuvに関する覚書(4) : スレッド uv_work_t, uv_async_t

何回かに分けて、libuvに関する備忘録を残しておく。

そもそもlibuvとは?

Linuxには、もともとlibeventlibevなどイベントループを使ったコールバック処理を簡単に実装できるライブラリが存在していおり、このlibuvはlibevなどのライブラリをクロスプラットフォーム化したようなライブラリで、Node.jsなどのコア機能として使われている。

今回Node.jsのアドオンを開発するにあたって、libuvを使って実装するために初歩的なことから初めてみた次第である。クロスプラットフォーム化されているが、とりあえずLinux上で実行する前提で開発を進める。基本的には、ドキュメントや付属のサンプルを試しただけである。

libuvのインストール準備

github libuv
libuv

aptコマンドで以下をインストールしておく。

> sudo apt install libuv1 libuv1-dbg libuv1-dev

uv_ub_tを使ったタイマー処理

タイミングの違う2つのタイマーeventを生成する。
uv_unref()をコールしないときとするときで結果が違う。
イベントループは、登録されたイベントに対して内部的に参照カウンタを付与して、イベントがなくなるまでループし続ける。uv_unrefで指定したイベントtimer1の参照を削除して、timer2のイベントが終了(第4引数がゼロで、リピートなし)したときに停止する動きになる。

#include <uv.h>

int main() {
    loop = uv_default_loop();

    uv_timer_init(loop, &timer1);
    uv_timer_init(loop, &timer2);

    // uv_unref()を実行して、timer1を参照カウンタ?から除外する
    // そうするとtimer2を1回だけ実行すると、イベントループに残っている
    // ハンドルがなくなってそこで終了する
    // uv_unref()を実行しない場合は、timer1が延々続く
    // comment out : timer1->timer1->timer1->timer1->timer2->timer1..
    // comment out : timer1->timer1->timer1->timer1->timer2
    uv_unref((uv_handle_t*) &timer1);

    // start 0sec, repeat 1000ms
    uv_timer_start(&timer1, callback_timer1, 0, 1000);
    // start 3000ms, repeat none.
    uv_timer_start(&timer2, callback_timer2, 3000, 0);

    return uv_run(loop, UV_RUN_DEFAULT);
}

タイマーのコールバック関数I/Fは、callback(uv_timer_t *handle)になる。下記のように、ハンドラを使って一時停止(uv_timer_stop)や再開(uv_timer_again)も可能。

uv_loop_t *loop;
uv_fs_event_t fs_event_req;
uv_timer_t timer1;
uv_timer_t timer2;

void callback_timer1(uv_timer_t *handle) {
    fprintf(stderr, "callback_timer1\n");

    uv_timer_stop(&timer1);
    // heavy process
    //sleep(1);
    uv_timer_again(&timer1);
}

void callback_timer2(uv_timer_t *handle) {
    fprintf(stdout, "callback_timer2\n");
    
}

ビルドと実行

> clang -luv sample.c -o timer
> ./timer
callback_timer1
callback_timer1
callback_timer1
callback_timer2
>