> > Note that there is another implementation problem: Scheme mutexes can
> > be unlocked by a different thread than the owner. Some thread systems
> > don't support this (for example POSIX threads). Fortunately, the
> > semantics of mutexes proposed can be implemented with a lower-level
> > mutex and a condition variable. So supporting mutex-owner is not an
> > additional overhead.
>
> One could of course remove the ability for a different thread to
> unlock the mutex, but I guess the proposed behaviour is more natural
> in the kind of interactive development environment which Scheme
> systems normally provide.
True. For example it allows someone that is debugging a program to
forcibly unlock a mutex that is known to be in the wrong state
(e.g. the program did not contain a mutex-unlock! at the right place).
Moreover the rule that only the owner thread can unlock a mutex is
artificial and probably an attempt by the designers of these systems
to enforce a particular discipline of using mutexes to implement
critical sections. The "Scheme way" removes artificial restrictions
whenever possible to give the programmer more freedom in terms of
programming styles. Just to give a simple example of what you can do
if any thread can unlock a mutex, imagine you want to implement a
(depth one) mailbox object that is used for interthread communication:
any thread can deposit an object in the mailbox and any thread can get
the object from the mailbox. I'll use a message passing style
(untested code...):
(define (make-empty-mailbox)
(let ((put-mutex (make-mutex)) ; allow put! operation
(get-mutex (make-mutex (current-thread))) ; prevent get! operation
(cell #f))
(define (put! obj)
(mutex-lock! put-mutex) ; prevent put! operation
(set! cell obj)
(mutex-unlock! get-mutex)) ; allow get! operation
(define (get!)
(mutex-lock! get-mutex) ; wait until object in mailbox
(let ((result cell))
(set! cell #f) ; prevent space leaks
(mutex-unlock! put-mutex) ; allow put! operation
result))
(lambda (msg)
(case msg
((put!) put!)
((get!) get!)
(else (error "unknown message"))))))
(define (mailbox-put! m obj) ((m 'put!) obj))
(define (mailbox-get! m) ((m 'get!)))
If you wanted to do this with owner-only-can-unlock mutexes, you need
to use condition variables (and a mutex) and the code is quite a bit
more complex for this relatively simple task. Here is an attempt
(untested code):
(define (make-empty-mailbox)
(let ((mutex (make-mutex))
(put-condvar (make-condition-variable))
(get-condvar (make-condition-variable))
(full? #f)
(cell #f))
(define (put! obj)
(mutex-lock! mutex)
(let loop ()
(if full?
(begin
(condition-variable-wait! put-condvar mutex)
(loop))
(begin
(set! cell obj)
(set! full? #t)
(mutex-unlock! mutex)
(condition-variable-signal! get-condvar)))))
(define (get!)
(mutex-lock! mutex)
(let loop ()
(if (not full?)
(begin
(condition-variable-wait! get-condvar mutex)
(loop))
(let ((result cell))
(set! cell #f) ; avoid space leaks
(set! full? #f)
(mutex-unlock! mutex)
(condition-variable-signal! put-condvar)))))
(lambda (msg)
(case msg
((put!) put!)
((get!) get!)
(else (error "unknown message"))))))
Marc