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はこれをサポートするハードウェア機能を持っていた。