[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re. Java solution of checking suspended threads !



//{{{}}}

Gerald,

> Subject: Java solution of checking suspended threads !

I don't think your solution works ...

//{{{  why not?

It works in the "ThingTest" program because I made sure the second thread
(that's the one that has to enquire about the first thread) didn't do
anything until well after the first thread had suspended itself.  When
it enquires with "thing.isSuspended", it certainly now gets the right
answer.

But what happens if the two threads are running together?  I'm assuming we
can make no assumptions about when a thread may be descheduled ... i.e. that
the underlying threads kernel is free to force a thread to yield any time
it likes ... the only rules being those relating to synchronize/wait/notify.
In that case, the following may (and does!) happen:

//{{{  thread activity against time diagram (time advances down the page)

     first thread                     second thread
     ------------                     -------------

     starts ...                       starts ...

     computes ...                     computes ...

     calls "this.Suspend()"
       sets "suspendflag = true"
                                      calls "first.isSuspended"
                                      gets back a "true"
                                      calls "first.Resume()", which
                                        sets "suspendflag = false" and
                                        calls "first.resume()", which
                                        doesn't do anything
       calls "super.suspend"

       <suspendflag is false,         <thinks first has been resumed>
        but is suspended>

//}}}

Big trouble!

//}}}
//{{{  can it be fixed?

The problem is that the sequence of instructions within the "Suspend" method:

  public void Suspend() {
    suspendflag = true;
    super.suspend();
  }

needs to be not interruptible.  At the moment, the first thread can be
executing "this.Suspend" concurrently with the second thread making the
"first.isSuspended" enquiry.  The setting of the "suspendflag" and the
actual "suspend()" operation is a critical region and needs to be made
atomic.

//{{{  public synchronized void Suspend()      // this doesn't help!

Turning "public void Suspend()" into "public synchronized void Suspend()"
makes these actions atomic (with respect to other threads trying to
execute other synchronized methods of this object) but has a disastrous
side-effect ... the thread executing a synchronized "Suspend()" hangs
on to the monitor!

That prevents the "isSuspended()" method being made synchronized, since that
would prevent a second thread ever getting an answer from the object whose
thread had executed "Suspend()".

But if the "isSuspended()" method is not synchronized, it can be run
interleaved with an execution of "Suspend()", even though that is synchronized,
and we are back where we started!

Catch-22 ...

//}}}

Oh dear ...

//}}}
//{{{  what about the IllegalThreadStateException?

You mentioned a "ServiceException" that can get thrown when a "suspend()"
is attempted by a thread that doesn't have authority to suspend the thread
indicated.  That's not my problem here ... the ThingTest thread does have
authority to suspend the thing thread ... it declared it after all.

But what about the note in Sun's Java Tutorial I quoted:

//{{{  what Sun says

According to Sun's "Java Tutorial":

> IllegalThreadStateException
>
>      The runtime system throws an IllegalThreadStateException
>      when you call a method on a thread and that thread's state
>      does not allow for that method call. For example,
>      IllegalThreadStateException is thrown when you call
>      suspend() on a thread that is not "Runnable".

//}}}

That doesn't talk about access rights ... it talks about "Runnable".
Elsewhere in the Tutorial, it describes the states a thread can be in
as "NotStarted", "Running", "Runnable", "Blocked" and "Stopped".  The
accompanying state transition table clearly shows the thread state changing
from "Running" or "Runnable" to "Blocked" upon execution of a "suspend()".

So, why doesn't "IllegalThreadStateException" get thrown when I execute
"suspend()" on a previously suspended thread?  Maybe, this facility is
just not implemented (yet, hopefully).  Where do I go for an answer?!!
What's Sun's Java hotline?!!

//}}}

Cheers,

Peter.