dyncompでWindowsネイティブスレッド

Gauche の拡張パッケージに dyncomp というものがある。
http://homepage.mac.com/naoki.koguro/prog/dyncomp/index-j.html
S 式で表現された C で関数を作ることが出来るライブラリだ。 記述した関数は Tiny C Compiler を用いてネイティブコードにコンパイルされるので高速に動作することが期待できる。 Gauche の通常の関数と同様に呼出すことが出来て高階関数もなんのその。
Gauchegauche.cgen.cise モジュールを使っているそうだ。 このモジュールはまだマニュアルにも記載されておらず、 dyncomp 自体のマニュアルもそれほど親切ではないので使い方がわかり難くはあるのだけれど、それはそれでかえって面白味があって良い。
で、ちょっとばかり遊んでみようと思って普通に Gauche を使っているだけでは出来ないことを考えたところ、 Windows のスレッド関係の API を呼んでみようと思い至った。 Mingw 版の Gauche はネイティブスレッドを扱えないので、 dyncomp 経由だとどうなるのかと思った次第だ。

(use dyncomp)

(cinclude "windows.h")
(cinclude "stdio.h")
(cinclude "process.h")

(define-cfn thread-proc ((data :: |void *|)) :: |unsigned int __stdcall|
  (let* ((i :: int 0))
    (loop
     (if (== i 10) (break))
     (sleep 1000)
     (printf "a")
     (set! i (+ 1 i)))
    (_endthread)))

(define-cproc thread-make&wait ()
  (let* ((thread-id :: |unsigned int|)
         (hThread :: |unsigned long|))
    (set! hThread (_beginthreadex NULL 0 thread-proc NULL 0 (& thread-id)))
    (WaitForSingleObject (cast HANDLE hThread) INFINITE)
    ))

(thread-make&wait)

意外にも期待通りに動作した。 とは言え、この例はスレッドを作ってから消えるまでメインスレッドは待機しているだけだし、 Scheme の世界と C の世界の間でとりたてて資源のやりとりを行なっていない。 もうちょっと凝ったことをやろうとすれば簡単にメモリリークとかオブジェクトの消滅とか起りそうな気がする。 (Gauche のコンパイル時に Boehm GC にスレッド関係の指定を付けたらいいかな? そんな安易な話ではないか…。)
色々といじめてみたいので、まずは使い方をちゃんと把握するところから始めよう。
Document ID: 11bcf2ac8b40bf90d509473e87a8e069