タイマー関数
ある関数を周期的に呼び出すには、POSIXタイマーやSIGALRMのようにシグナルハンドラを使うことになるけど、Infernoだとチャネルの同期的な性質を利用して、次のように書ける。
implement Timer; include "sys.m"; include "draw.m"; sys : Sys; Timer : module { init : fn(nil : ref Draw->Context, nil : list of string); }; init(nil : ref Draw->Context, nil : list of string) { sync := chan of int; n := 10; sys = load Sys Sys->PATH; spawn timer(sync, n); for (i := 0; i < n; i++) { <- sync; sys->print("%d\n", i); } } timer(sync : chan of int, n : int) { for (i := 0; i < n; i++) { sys->sleep(1000); sync <-= 1; } }
変数syncが同期に使っているチャネルだ。
ちなみに、このプログラム実行時にpsでスレッドの状態を見てみると次のようになる。
% ps | grep Timer 34 19 oraccha 0:00.0 recv 73K Timer 35 19 oraccha 0:00.0 release 1K Timer[$sys]
5カラム目がスレッドの状態である。Recvはチャネルの受信待ち状態で、メインスレッドが"<- sync;"で待っていることを意味する。当然、Sendという送信待ち状態も存在する。もう一方のスレッド(spawnしたtimerスレッド)の状態はreleaseと表示されている。これはDis VMのレディキューから切り離され、組込みモジュールの実行完了を待っていることを意味する。組込みモジュールということはCで実装されているので、Dis VMの管理外ということになる。"[$sys]"という表示から察しがつくように、Sysモジュール、つまりこの場合はsleep()待ちしている状態である。
スレッドの状態を列挙すると、alt、broken、exiting、ready、recv、release、sendとなる。馴染みがないのはaltという状態だろうが、これは次のエントリで紹介するalt文での待ち状態になる。