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 Marc Feeley 27 Apr 2000 01:27 UTC

> 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".

You are right, there is an error in my code.  I meant to start
the get-mutex in the locked/not-owned state:

 (define (make-empty-mailbox)
   (let ((put-mutex (make-mutex)) ; allow put! operation
         (get-mutex (make-mutex))
         (cell #f))

     ...

     (mutex-lock-anonymously! get-mutex) ; prevent get! operation

     (lambda (msg) ...)))

>         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?

Under what authority does T3 terminate T1?  As I have pointed out in
the spec, thread-terminate! must be used very carefully to avoid
stopping a thread at an "unsafe" point (such as in the middle of a
critical section).  If T3 needs to terminate T1 then there is a close
coupling between the two (i.e. whoever implements T3 must know how T1
is implemented).

Unfortunately, I don't see any simple way to write the mailbox example
using the mutex operations currently available such that it is
possible to cleanly terminate threads, even if T3 and T1 cooperate.

I'll give it some thought but am open to suggestions.

Marc