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

Re: Multi-CHAN_OF_INT



Oyvind asks:

> 1. How is flow through a CHAN_OF_INT if
>    One tx and several rx?
>     It does not seem to be a brodcast (from code inspection),
>     but a "whoever is the the next rx gets the next tx INT)

Right.

>     In case I am right, when is such a scheme wanted?

The Tx has some important data that needs to be acted upon by any one of
a number of Rx servers ... the Tx doesn't care which Rx takes it, but does
care that one of them does and cannot proceed until that happens.

Solution: connect up the Tx and multiple Rxs through a CHAN_OF_INT.

CHAN_OF_INT also allows the Tx to have lots of competitor Txs seeking the
attention of any of the same group of Rxs ...

Note: for practical use, CHAN_OF_INT needs to be generalised to an occam3
CALL channel ...

Note: Brinch-Hansen's SuperPascal has dynamically created channels visible
and accessible to any number of processes.  They are to be used for strict
synchronisation between one reader and one writer.  The particular readers
and writers using the channel can change from communication to communication.
If one reader tries to read the channel follwed by a second reader (rather
than a matching writer), this is a run-time error!  Thus, SuperPascal has
the original version of CHAN_OF_INT ... usable by multiple readers and
writers ... but not safely usable!!  With the new CHAN_OF_INT, the second
reader in the above scenario would safely be queued on the read_monitor.

I don't really know if the multi-reader/writer channel is useful but:

  o it might be;
  o Brinch-Hansen seems to be saying that dynamically accessible channels
    are more powerful than occam's private-between-two-processes channels;
  o all Java objects are at the mercy of multiple thread calls anyway,
    so it seems good practice to make them multiple-thread-safe!

>   class MONITOR
>   {
>     // Empty class, with no data and no metods
>     // It becomes a Java object that inherits its own monitor (used)
>     // and its notify and wait (*not used*)
>     // notify and wait are final and cannot be overridden. Is there 
>     // a way to make their use illegal in this context, see later
>   }

Dunno.  Although not used in CHAN_OF_INT, I suspect that the inherited
notify and wait methods on instances of such a MONITOR could be very useful.
See the "PlingTest.java" code enclosed below.

> 3. In the Java library source code it says that
>    "The method wait() can only be called from within a synchronized method"
>    "The method notify() can only be called from within a synchronized method"
>    I gather this must be meant literally also to cover "or withing a
>    synchronized block" ? 

Experiment with the JDK says yes!  Other experiments show that notify can be
called from outside a synchronized method/block but that nothing happens.
The wait method can be called only whilst holding the monitor whose
wait you are calling (i.e. you must be inside a relevant synchronized
section), otherwise it's a run-time error which kills the erroneously
calling thread ... that seems fine.  I would have thought the same ought
to happen to a thread that calls notify whilst not holding the monitor
whose notify you are calling ...

>   wait ();                  // How do we know that this and ..
>   // this.wait ();          // this is the same, and not ..
>   // read_monitor.wait ();  // equal to this or ..
>   // write_monitor.wait (); // this? Scoping rules?
> 
>   notify ();                  // How do we know that this and ..
>   // this.notify ();          // this is the same, and not ..
>   // read_monitor.notify ();  // equal to this or ..
>   // write_monitor.notify (); // this? Scoping rules?

"wait ()", with no object qualifier, seems to mean "this.wait ()".  Similarly,
"notify ()", with no object qualifier, is "this.notify ()".

>   In the view of this, I would have explicitly stated "this.wait()" etc.

That's probably good practice.

>   If an occam variable is taken out of scope by another variable with
>   the same name, the old is in fact taken out of scope. 

I don't think scoping rules come into it here.  In the "read" method,
I could have called "read_monitor.wait ()", "write_monitor.wait ()" or
"this.wait ()" ... any are available to be called.  The first would have
given the wrong semantics for the method (but would execute OK).  The
second would give a run-time error and kill the calling thread.  The
last is what is wanted ... I just wrote "wait ()" for shorthand ...

Cheers,

Peter.

PS. Enclosed is a test program designed to find out whether executing
    a wait released only the monitor whose wait is being called or
    whether it released all monitors currently held by the thread.
    The answer, needed for the correct functioning of the multiple
    reader/writer CHAN_OF_INT and BUFFER_OF_INT, is the former.
    
    The example shows the use of calling wait and notify on instances
    of these empty MONITOR classes.  "One" and "Two" have similar
    behaviours except that "One" want to sync with "susie" (after 5 secs)
    and "Two" wants to sync with "sally" (after 10 secs).  Unfortunatley,
    "Zero" grabbed both "susie" and "sally" straight away (after 0 secs),
    but then executed "susie.wait".  That released "susie" ... but did
    it also release "sally"?  Answer: no!!  You will see the "One" syncs
    with "susie" upon request, but that "Two" has to wait for "Zero" to let
    "sally" go (which "Zero" doesn't until thumped by "Three") ... it's
    a bit politically incorrect ...

(cut here)
-----------------------------------------------------------------------------
//{{{}}}

//{{{ PlingTest.java

//{{{  imports
import java.io.*;
import java.util.*;
import java.lang.*;
//}}}

//{{{  class Pling {
class Pling {
}
//}}}
//{{{  class Zero  extends Thread {  // -> sally -> susie -> susie.wait()
class Zero  extends Thread {  // -> sally -> susie -> susie.wait()
  Pling sally, susie;
  //{{{  public Zero (Pling sally, Pling susie) {
  public Zero (Pling sally, Pling susie) {
    setName ("Zero");
    this.sally = sally;
    this.susie = susie;
    start ();
  }
  //}}}
  //{{{  public void run () {
  public void run () {
    System.out.println ("    " + getName() + " " + toString());
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Zero: trying to sync with sally ...");
    synchronized (sally) {
      System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                          " Zero: got sally, trying to sync with susie ...");
      synchronized (susie) {
        System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                            " Zero: got sally and susie, now susie.wait() ...");
        //{{{  wait ();
        try {
          susie.wait ();
        } catch (InterruptedException e) {
        }
        //}}}
        System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                            " Zero: must have been notified, releasing susie ...");
      }
      System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                          " Zero: releasing sally ...");
    }
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Zero: terminating ...");
  }
  //}}}
}
//}}}
//{{{  class One   extends Thread {  // sleep (5000) -> susie
class One   extends Thread {  // sleep (5000) -> susie
  Pling susie;
  //{{{  public One (Pling susie) {
  public One (Pling susie) {
    setName ("One");
    this.susie = susie;
    start ();
  }
  //}}}
  //{{{  public void run () {
  public void run () {
    System.out.println ("    " + getName() + " " + toString());
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " One: about to sleep (5000) ...");
    //{{{  sleep (5000);
    try {
      sleep (5000);
    } catch (InterruptedException e) {
    }
    //}}}
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " One: woken up ... about to sync with susie ...");
    synchronized (susie) {
      System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                          " One: got susie, now letting her go ...");
    }
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " One: terminating ...");
  }
  //}}}
}
//}}}
//{{{  class Two   extends Thread {  // sleep (10000) -> sally
class Two   extends Thread {  // sleep (10000) -> sally
  Pling sally;
  //{{{  public Two (Pling sally) {
  public Two (Pling sally) {
    setName ("Two");
    this.sally = sally;
    start ();
  }
  //}}}
  //{{{  public void run () {
  public void run () {
    System.out.println ("    " + getName() + " " + toString());
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Two: about to sleep (10000) ...");
    //{{{  sleep (10000);
    try {
      sleep (10000);
    } catch (InterruptedException e) {
    }
    //}}}
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Two: woken up ... about to sync with sally ...");
    synchronized (sally) {
      System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                          " Two: got sally, now letting her go ...");
    }
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Two: terminating ...");
  }
  //}}}
}
//}}}
//{{{  class Three extends Thread {  // sleep (15000) -> susie -> susie.notify
class Three extends Thread {  // sleep (15000) -> susie -> susie.notify
  Pling susie;
  //{{{  public Three  ()
  public Three (Pling susie) {
    setName ("Three");
    this.susie = susie;
    start ();
  }
  //}}}
  //{{{  public void run () {
  public void run () {
    System.out.println ("    " + getName() + " " + toString());
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Three: about to sleep (15000) ...");
    //{{{  sleep (15000);
    try {
      sleep (15000);
    } catch (InterruptedException e) {
    }
    //}}}
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Three: woken up ... about to sync with susie ...");
    synchronized (susie) {
      System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                          " Three: got susie, about to susie.notify ...");
       susie.notify ();
      System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                          " Three: notified OK, releasing susie ...");
    }
    System.out.println ("(timestamp = " + System.currentTimeMillis() + ")" +
                        " Three: terminating ...");
  }
  //}}}
}
//}}}
//{{{  class PlingTest
class PlingTest {
  //{{{  public static void main (String argv [])
  public static void main (String argv []) {
  
    Pling sally = new Pling ();
    Pling susie = new Pling ();
  
    Zero zero   = new Zero (sally, susie);   // -> sally -> susie -> susie.wait()
    One one     = new One (susie);           // sleep (5000) -> susie
    Two two     = new Two (sally);           // sleep (10000) -> sally
    Three three = new Three (susie);         // sleep (15000) -> susie -> susie.notify
  
    System.out.println ("main started ...");
  }
  //}}}
}
//}}}


//}}}
-----------------------------------------------------------------------------
mint.ukc.ac.uk% java PlingTest
    Zero Thread[Zero,5,main]
(timestamp = 832850755294) Zero: trying to sync with sally ...
(timestamp = 832850755313) Zero: got sally, trying to sync with susie ...
(timestamp = 832850755330) Zero: got sally and susie, now susie.wait() ...
    One Thread[One,5,main]
(timestamp = 832850755350) One: about to sleep (5000) ...
    Two Thread[Two,5,main]
(timestamp = 832850755381) Two: about to sleep (10000) ...
    Three Thread[Three,5,main]
(timestamp = 832850755400) Three: about to sleep (15000) ...
main started ...
(timestamp = 832850760371) One: woken up ... about to sync with susie ...
(timestamp = 832850760381) One: got susie, now letting her go ...
(timestamp = 832850760390) One: terminating ...
(timestamp = 832850765391) Two: woken up ... about to sync with sally ...
(timestamp = 832850770381) Three: woken up ... about to sync with susie ...
(timestamp = 832850770391) Three: got susie, about to susie.notify ...
(timestamp = 832850770401) Three: notified OK, releasing susie ...
(timestamp = 832850770410) Zero: must have been notified, releasing susie ...
(timestamp = 832850770421) Three: terminating ...
(timestamp = 832850770420) Zero: releasing sally ...
(timestamp = 832850770437) Two: got sally, now letting her go ...
(timestamp = 832850770445) Two: terminating ...
(timestamp = 832850770453) Zero: terminating ...
mint.ukc.ac.uk%
-----------------------------------------------------------------------------