読者です 読者をやめる 読者になる 読者になる

自由課題

学んだり、考えたり、試したりしたこと。

node.jsを支えるlibuvのチュートリアル"uvbook" :イベントループ

C node.js

この文書はuvbookの日本語翻訳の一部となります。文書そのものの説明その他については目次をご覧ください。

より進んだイベントループ

libuvはイベントループに対して相当な制御機構を提供しており、複数のイベントループで曲芸を行うことにより興味深い結果を得ることができます。また、libuvのイベントループを別のイベントループライブラリに組み込むことができます - Qt ベースのUIを考えてみてください。Qtのイベントループが集中的なシステムレベルのタスクを行うlibuvのバックエンドを駆動します。

イベントループを停止する

uv_stop() はイベントループを停止するために用いられます。ループは 次の繰り返しで 実行を停止します。これは現在の繰り返しで処理される準備ができているイベントは処理され、 uv_stop() はkill(訳注:即時に停止する)スイッチとしては使用できないことを意味しています。uv_stop が呼び出された時、ループはこの繰り返しのI/Oのためにブロックは されません。 これらのことの意味は少し理解しにくいので、 全ての制御フローが発生する場所で uv_run() を見てみましょう。

src/unix/core.c - uv_run

 while (r != 0 && loop->stop_flag == 0) {
    UV_TICK_START(loop, mode);

    uv__update_time(loop);
    uv__run_timers(loop);
    uv__run_idle(loop);
    uv__run_prepare(loop);
    uv__run_pending(loop);

    timeout = 0;
    if ((mode & UV_RUN_NOWAIT) == 0)
      timeout = uv_backend_timeout(loop);

stop_flaguv_stop() によって設定されます。現在イベントループ内で起動した全てのlibuvのコールバック(uv_stop() が起動する原因となったもの)は発生している現在の繰り返しを行っています。最初にlibuvはタイマを更新し、そのあとタイマを保留し、コールバックを準備し、待機中の全てのI/Oコールバックを起動します。もし ここで uv_stop() を呼び出したとしたら、 stop_flag がセットされます。これは uv_backend_timeout()0 を返却することに起因し、これがループがI/Oをブロックしない理由です。もし一方、 チェックハンドラの一つの uv_stop() を呼び出したら、I/Oは既に終了していて効力はありません。

uv_stop() は、結果がすでに得られている、もしくはエラーがある場合に全てのハンドラを一つ一つ停止させる必要なくループを停止するために有効です。

下記はループを停止させる例で、どう現在の繰り返しが発生するかを実演するものです。

uvstop/main.c

#include <stdio.h>
#include <uv.h>

int64_t counter = 0;

void idle_cb(uv_idle_t *handle, int status) {
    printf("Idle callback¥n");
    counter++;

    if (counter >= 5) {
        uv_stop(uv_default_loop());
        printf("uv_stop() called¥n");
    }
}

void prep_cb(uv_prepare_t *handle, int status) {
    printf("Prep callback¥n");
}

int main() {
    uv_idle_t idler;
    uv_prepare_t prep;

    uv_idle_init(uv_default_loop(), &idler);
    uv_idle_start(&idler, idle_cb);

    uv_prepare_init(uv_default_loop(), &prep);
    uv_prepare_start(&prep, prep_cb);

    uv_run(uv_default_loop(), UV_RUN_DEFAULT);

    return 0;
}

libuvのイベントループを他のライブラリに組み込む

TODO
Needs content (訳注:原文のまま)