[並行計算][Scheme][Racket] SRFI 18のmutexとcondition variable

RacketはSRFI 18に対応していることになっているが、mutex-lock!やcondition-variable-signal!などどの手続きはrequireしても定義されない。

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で定められた手続きが使える。

Leave a Reply

Your email address will not be published. Required fields are marked *

*