mutexやcondition variableのような同期機構ではなく、チャネル通信などの機構を使えということなのだと思うが、ロックを使ったほうが素直に実装できる場合もある。
幸いセマフォはあるようなので、セマフォでmutexやcondition variableを次のように書いた。
;;; mutex
(define (make-mutex)
(make-semaphore 1))
(define (mutex-lock! m)
(semaphore-wait m))
(define (mutex-unlock-primitive! m)
(semaphore-post m))
(define (mutex-unlock! m . rest)
(let ((condvar (if (null? rest) #f (car rest))))
(mutex-unlock-primitive! m)
(when condvar
(condition-variable-wait! condvar))))
;;; gate
(define (make-gate)
(make-semaphore 0))
(define (gate-wait! g)
(semaphore-wait g))
(define (gate-signal! g)
(semaphore-post g))
;;; condition variable
(define (make-condition-variable)
(list 'condition-variable '() (make-mutex)))
(define (condition-variable-gates cv)
(list-ref cv 1))
(define (condition-variable-mutex cv)
(list-ref cv 2))
(define (condition-variable-clear-gates! cv)
(set-car! (cdr cv) '() ))
(define (condition-variable-put-gates! cv val)
(set-car! (cdr cv)
(cons val (condition-variable-gates cv))))
(define (condition-variable-wait! cv)
(let ((mutex (condition-variable-mutex cv))
(gates (condition-variable-gates cv))
(new-gate (make-gate)))
(mutex-lock! mutex)
(condition-variable-put-gates! cv new-gate)
(mutex-unlock-primitive! mutex)
(gate-wait! new-gate)))
(define (condition-variable-signal! cv)
(let ((mutex (condition-variable-mutex cv))
(gates (condition-variable-gates cv)))
(mutex-lock! mutex)
(for-each (lambda (g) (gate-signal! g))
gates)
(condition-variable-clear-gates! cv)
(mutex-unlock-primitive! mutex)))
condition variableは使い捨てのmutexを用いて実装している。
これで、同期に関してSRFI 18で定められた手続きが使える。
調べてみると Racket ではペアへの破壊的な代入を許さないらしい。
代わりに mcons というデータ構造が用意されていてこちらは set-mcar! や set-mcdr! といった手続きで代入ができる。
R5RS に基づいて書かれた Scheme のプログラムを動かすにはペアを扱う手続きを mcons を使うものに定義し直す必要があるが、すでにそれをするパッケージが用意されている。
> (require r5rs)
とすると、set-car! や set-cdr! が定義され、cons で作ったペアに再代入できる。
]]>load で相対パスを使った場合は current-directory (デフォルトでは実行パス)を基点にロードパスが決まる。
ただ、”./filename” や “../filename” といった形式は使えなかった。
current-directory と結合してOSに丸投げするだけでいいのに、信じられない。
ロードされているファイルからそのファイルのあるディレクトリを基点に相対パスでロードする場合は load-relative を用いる。
(load-relative "relative-path")
その際、基点となるディレクトリは current-load-relative-directory 関数で取得できる。
]]>