Monitored dining philosophers example

This is an example that shows how to use user-defined monitors to establish communication between CPN Tools and an applet via external communication with Comms/CPN.

The net is a variation of the net for the Dining philosophers example. In the following it is assumed that you are familiar with the net for the Dining philosophers example.

In this net the philosophers pick up one chopstick at a time, whereas in the Dining philosophers example net, the philosophers pick up both the left and right chopsticks at the same time.

Dining Philosophers Monitored

This net can be found in <cpntoolsdir>/Samples/DiningPhilosophers/DiningPhilosophers_COMM_Mon.cpn where <cpntoolsdir> is the directory in which CPN Tools is installed.

The net can also be downloaded here.

The applet

A Java applet has been created to show how Comms/CPN can be used to establish communication between CPN Tools and an external process. This applet provides an alternative graphical representation of the markings of the net for the dining philosophers system. Each time a transition occurs in the net, the graphics shown by the applet are updated.

In the figure below, philosopher number 5 has both chopsticks and is eating, while philosopher number 2 has only picked up the right chopstick.

Dining Philosophers applet

The files for the applet can be found in <cpntoolsdir>/Samples/DiningPhilosophers/applet, or they can be downloaded from the help page for external communication with Comms/CPN.

The Java classes for the applet will not be described here.

Follow these steps to run the applet with the net described on this page:

  1. Start CPN Tools.
  2. Load the sample net DiningPhilosophers_COMM_Mon.cpn.
  3. Apply the Rewind tool to the net to return to the initial marking.
  4. Load the applet on the computer where CPN Tools is running, e.g. by double-clicking on the applet.html file.
  5. Apply the Play tool to the System page (the simulation feedback will not be updated until a connection has been made to the applet, see steps 6 and 7).
  6. Enter 9000 as the Port Number in the GUI for the applet.
  7. Press the Start button in the applet.
  8. Observe how the GUI for the applet reflects the marking of the CP-net.

Declarations for communication

There are two declarations that are used when communicating with the applet. The function send_to_applet uses one of the Comms/CPN functions to send a string to the applet. The reference variable connected is used in two user-defined monitors to check and/or indicate whether a connection to the applet has been established.

Declarations for communication

Communication using monitors and Comms/CPN

The two user-defined monitors for this net are named AppletComm and Deadlock. The AppletComm monitor is associated with all five transitions on page System, and the Deadlock monitor is associated with two transitions and two places on the same page.

Monitors using Comms/CPN

''AppletComm'' monitor

The AppletComm monitor is associated with all of the transitions in the net. This means that the predicate function for the monitor will be invoked after every step in a simulation.

Initialization function

The initialization function is called once before a simulation starts. It checks to see if a communication connection exists between CPN Tools and the applet. If there is a connection, then the connection is closed, and the reference variable connected is updated to indicate that the connection has been closed. The ConnManagementLayer.closeConnection function is one of the Comms/CPN functions.

fun init () =
  if !connected = true
  then (ConnManagementLayer.closeConnection("Conn 1");
        connected := false)
 else ()

Predicate function

The predicate function is invoked after every step in a simulation, and it returns true each time one of the transitions in the net occurs.

fun pred (bindelem) = 
let
  fun predBindElem (System'LeftFirst (1, {p})) = true
    | predBindElem (System'LeftScnd (1, {p})) = true
    | predBindElem (System'PutDown (1, {p})) = true
    | predBindElem (System'RightFirst (1, {p})) = true
    | predBindElem (System'RightScnd (1, {p})) = true
    | predBindElem _ = false
in
  predBindElem bindelem  
end

Observation function

The observation function is invoked each time the predicate function returns true, and it returns a pair of strings. The first value in the pair is a string representation of the variable p which is of type PH, and the second value is a string that indicates what event just occurred, i.e. which transition just occurred. The function PH.mkstr is one of the Color set functions.

fun obs (bindelem) = 
let
  fun obsBindElem (System'LeftFirst (1, {p})) = (PH.mkstr(p),"gotleft")
    | obsBindElem (System'LeftScnd (1, {p})) = (PH.mkstr(p),"eat") 
    | obsBindElem (System'PutDown (1, {p})) = (PH.mkstr(p),"think")
    | obsBindElem (System'RightFirst (1, {p})) = (PH.mkstr(p),"gotright")
    | obsBindElem (System'RightScnd (1, {p})) = (PH.mkstr(p),"eat")
    | obsBindElem _ = ("","")
in
  obsBindElem bindelem  
end

Action function

Whenever the predicate function returns true, the value that is returned by the observation function will be passed to the action function. The action function will check whether a connection to the applet has been established. If there is no connection, then ConnManagementLayer.acceptConnection function is invoked, and the simulation will be blocked until the applet opens a connection on port 9000. When a connection has been established, then the connected reference variable is set to true. Finally, the send_to_applet function is invoked with the string values that were passed from the observation function. The send_to_applet is defined in a declaration, as described above.

fun action (s1,s2) = 
  (if not(!connected)
  then (ConnManagementLayer.acceptConnection("Conn 1",9000);
        connected:=true)
  else ();
  send_to_applet(s1,s2))

Stop function

The stop function is invoked when simulation stop criteria are fulfilled. If there is still a connection between CPN Tools and the applet, then the connection will be closed, and the reference variable connected will be set to false. If the connection has already been disconnected, then nothing will happen when the stop function is invoked.

fun stop () = 
  if !connected = true
  then (ConnManagementLayer.closeConnection("Conn 1");
        connected := false)
 else ()

''Deadlock'' monitor

The Deadlock monitor is used to close the communication connection between CPN Tools and the applet if a simulation ends in a dead marking, i.e. in a marking in which there are no more enabled transitions. There are two dead markings for this net:

  • When all philosophers have taken their left chopstick
  • When all philosophers have taken their right chopstick

All philosophers have their left chopstick if the marking of place GotLeft is equal to all of the values in the PH color set, i.e. if the marking of the place is equal to the multiset returned by the function PH.all(). The function PH.all() is one of the Color set functions. Checking whether all philosophers have their right chopstick is done in a similar manner.

The Deadlock monitor is associated with the nodes shown in the group below.

Nodes associated with Deadlock monitor

Initialization function

The initialization function for this monitor does nothing.

fun init (System'GotLeft_1_mark : PH ms, 
          System'GotRight_1_mark : PH ms) = ()

Predicate function

The predicate function checks to see whether a dead marking has been reached. The predicate function is invoked when either the LeftFirst or the RightFirst transitions occur. The predicate function will return true in the two following situations:

  • The LeftFirst transition has occurred and all philosophers have their left chopstick
  • The RightFirst transition has just occurred and all philosophers have their right chopstick

The == operator is used to check if two multisets are equal.

fun pred (bindelem, 
          System'GotLeft_1_mark : PH ms, 
          System'GotRight_1_mark : PH ms) = 
let
  fun predBindElem (System'LeftFirst (1, {p})) = 
                    System'GotLeft_1_mark == PH.all()
    | predBindElem (System'RightFirst (1, {p})) = 
                      System'GotRight_1_mark == PH.all()
    | predBindElem _ = false
in
  predBindElem bindelem  
end

Observation function

The observation function for this monitor does nothing, and it returns a unit value.

fun obs (bindelem, 
         System'GotLeft_1_mark : PH ms, 
         System'GotRight_1_mark : PH ms) =  ()

Action function

The action function is used to close a connection between CPN Tools and the applet when a dead marking has been reached. When the action function is invoked, it will send the string “deadlocked” to the applet, it will close the connection to the applet, and it will set the reference variable connected to false.

fun action (observedval) =
  (ConnManagementLayer.send("Conn 1","deadlocked",stringEncode);
   ConnManagementLayer.closeConnection("Conn 1");
   connected := false);

Stop function

The stop function for this monitor does nothing.

fun stop (System'GotLeft_1_mark : PH ms, 
          System'GotRight_1_mark : PH ms) = ()