エラトステネスのふるい
libtaskはチャネルにも対応している。ということで、Limboで書いたエラトステネスのふるいをC + libtaskで書き直してみた。Plan9日記では何度もチャネルを取り上げているが、チャネルはタスク間でメッセージをやり取りするための通信手段を提供する。chancreate関数の第2引数が0なので、バッファは使わない。したがって、あるタスクがメッセージをchansendすると、他のタスクがそのチャネルからchanrecvするまで、そのタスクはブロックされる。
やっぱり、型の扱いがLimboの方が書きやすいな。Limboではチャネルに型があって、send/recv("<-"という演算子が使われる)すればいいんだけど、libtask(C)だとデータ型に応じて、chansend, chansendp, chansendul関数を使い分ける必要がある。Limboとの違いは、channbsend([p|ul])というノンブロッキング版が用意されていることだろうか。
#include <stdio.h> #include <stdlib.h> #include "task.h" enum { STACK = 32768 }; int max = 100; void sievetask(void *arg) { Channel *c = (Channel *)arg; Channel *nc; int p, n; p = chanrecvul(c); if (p >= max) taskexitall(0); printf("%d\n", p); nc = chancreate(sizeof(int), 0); taskcreate(sievetask, nc, STACK); for (;;) { n = chanrecvul(c); if (n % p) chansendul(nc, n); } } void taskmain(int argc, char **argv) { Channel *c; int i = 2; if (argc == 2) max = atoi(argv[1]); c = chancreate(sizeof(int), 0); taskcreate(sievetask, c, STACK); for (;;) chansendul(c, i++); }