alt
チャネルを使ってプログラムを組むと、一つのスレッドで複数のチャネルからの入出力を待ちたくなる。UNIXでいうところのselect/pollのように。そこで使うのが、alt文*1。
ここではtkcmdというTKインタプリタ(?)からコードを引用している。見た目はcase文に近いが、"=>"の左辺(ガード?)はチャネルの入出力になる。例えば、キーボードから入力があったら、tk->keyboard()を呼んで、マウスから入力があったら、tk->pointer()を呼ぶという処理を行っている。イベントループとして使うには、alt文を無限ループで囲む。
for(;;) alt {
c := <-wm.kbd =>
tk->keyboard(Wwsh, c);
m := <-wm.ptr =>
tk->pointer(Wwsh, *m);
c := <-wm.ctl or
c = <-Wwsh.wreq =>
tkclient->wmctl(Wwsh, c);
line := <-lines =>
if (line == nil)
break Loop;
if (line[0] == '#')
break;
line = line[0:len line - 1];
result := tk->cmd(Wwsh, line);
if (result != nil)
sys->print("#%s\n", result);
if (update)
tk->cmd(Wwsh, "update");
sys->print("%s", ps1);
menu := <-winctl =>
tkclient->wmctl(Wwsh, menu);
s := <-output =>
sys->print("#<stdout>%s\n", s);
sys->print("%s", ps1);
}tkcmdを実行してから、psの結果を見ると、alt状態でブロックされていることがわかる。
123 123 oraccha 0:00.0 alt 77K Tkcmd
124 2 oraccha 0:00.0 alt 13K Wmsrv
125 123 oraccha 0:00.0 release 16K Bufio[$sys]IPWLには、alt文の注意点として、複数のスレッドから同時にチャネルに読み書きできない("channel busy"エラーが発生する)という制限があると書かれていたけど、次のプログラムはちゃんと動くようだな。emuだと動くのか、4th editionで改善されたのか?
implement Test;
include "sys.m";
include "draw.m";
Test : module
{
init : fn(nil : ref Draw->Context, nil : list of string);
};
init(nil : ref Draw->Context, nil : list of string)
{
channel := chan of int;
spawn writer(channel);
spawn writer(channel);
spawn reader(channel);
spawn reader(channel);
}
writer(channel : chan of int)
{
for(;;) alt
{
channel <-= n =>
}
}
reader(channel : chan of int)
{
for(;;) alt
{
<- channel =>
;
}
}altは選択可能なケースが発生するまで待機する。一方、複数のケースが選択可能な場合はいずれか一つがランダムに選択される。この挙動はNewsqueakのselectと同じ。
*1:この構文はOccamのALTが由来だと思われる。Newsqueakではselect〜case文を使っていたので。ちなみにTransputerはこれをサポートするハードウェア機能を持っていた。