Re: non critical-section uses of mutexes oleg@xxxxxx (26 Apr 2000 22:00 UTC)
Re: non critical-section uses of mutexes Marc Feeley (27 Apr 2000 01:27 UTC)

Re: non critical-section uses of mutexes oleg@xxxxxx 26 Apr 2000 21:58 UTC

Marc,

	I'm afraid there is another problem with your mailbox
solution. Consider the corrected 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-anonymously! put-mutex) ; prevent put! operation
          (set! cell obj)
          (mutex-unlock! get-mutex)) ; allow get! operation

        (define (get!)
          (mutex-lock-anonymously! 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"))))))

Let thread T1 execute
	(set! global-mbox (make-empty-mailbox))

and yield control to T2, which will do
	((global-mbox 'get!))
This will immediately block T2. The control reverts to T1. Suppose
that T1 terminates right away. global-mbox::get-mutex was locked by T1
upon mailbox creation.  After T1 is gone, the mutex becomes abandoned,
so T2 all of the sudden gets "abandoned mutex exception".

	It gets worse. Suppose T1 runs
        (set! global-mbox (make-empty-mailbox))
	((global-mbox 'put!) 'value)
	((global-mbox 'get!))
However, in the middle of ((global-mbox 'get!)), right after
executing (set! cell #f) but _before_ (mutex-unlock! put-mutex),
thread T1 exhausts its quantum and is kicked off the CPU. Suppose
thread T3 gets control, and forcibly terminates T1. T1 is not running,
so it dies instantly. However, the global-mbox::get-mutex does not
become abandoned, because it was locked anonymously. So,
global-mbox::get-mutex remains locked, and so does
global-mbox::put-mutex (because T1 lost CPU control before it could
unlock the mutex). Thus both mailbox mutexes are locked, and no one
can put to or take anything from the mailbox. If some threads were
waiting on put!, they will wait forever. Wasn't mutex ownership
introduced to specifically prevent this kind of problem?