CS 133 Discussion: Week 8

An undergraduate working for us got a job and will be leaving soon. We need someone to replace him. This could be a 199 or an RAship. (An RAship means you would get paid.)

Homework 3: Java RMI

I changed/clarified the assignment quite a bit. Please revisit the assignment web page.

There are a whole lot of steps to writing a Java RMI program. It's easier than CORBA, but not to the same degree that Java Sockets are easier than C sockets.

  1. Start by writing an interface that extends Remote.
    package prog3;
    
    import java.rmi.Remote; 
    import java.rmi.RemoteException; 
    
    public interface AllPairsInterface extends Remote { 
      String getHostName() throws RemoteException;
      int[]  getRow(int rowNumber) throws RemoteException;
      void   putRow(int rowNumber, int row[]) throws RemoteException;
    }
    
    You have to put everything in a package. I called mine prog3, and it has to go in a directory named prog3, and you have to define CLASSPATH to be the directory above prog3. Each method must throw RemoteException.

  2. After creating the interface, you create a class to implement the interface.
    package prog3;
    
    import java.net.InetAddress;
    import java.rmi.Naming;
    import java.rmi.RemoteException;
    import java.rmi.RMISecurityManager;
    import java.rmi.server.UnicastRemoteObject;
    
    public class AllPairsServer extends UnicastRemoteObject
      implements AllPairsInterface {
    
      private String machineName;
      private int adjacency[][];
    
      public AllPairsServer() throws RemoteException {
        super();
      }
    
      public String getHostName() throws RemoteException {
        return machineName;
      }
    
      public int[] getRow(int rowNumber) throws RemoteException {
        return adjacency[rowNumber];
      }
    
      public synchronized void putRow(int rowNumber,
                                      int row[]) throws RemoteException {
        adjacency[rowNumber] = row;
      }
    
      public static void main(String args[]) { 
    
        String serverName;
    
        // Create and install a security manager 
        if (System.getSecurityManager() == null) { 
          System.setSecurityManager(new RMISecurityManager()); 
        } 
        try { 
          AllPairsServer server = new AllPairsServer();
          // Bind this object instance to the name "HelloServer"
          machineName = InetAddress.getLocalHost().getHostName();
          serverName = "//" + machineName + ":" + portNumber + "/AllPairsServer";
          Naming.rebind(serverName, server); 
          System.out.println("Server " + serverName + " bound in registry"); 
        } catch (Exception e) { 
          System.out.println("Server initialization error: " + e.getMessage()); 
          e.printStackTrace();
        }
      } 
    }
    

  3. Now you have a server. You need to compile it and register it on the system.
    javac AllPairsInterface.java
    javac AllPairsServer.java
    rmic -d $HOME prog3.AllPairsServer
    
    For no good reason, I set my CLASSPATH to be my home directory. My class files go in $HOME/prog3 (since prog3 is the package name). Note the rmic command requires the full package qualified name of the class, not the Java file.

  4. You register the object with the rmiregistry with the following commands.
    unsetenv CLASSPATH
    rmiregistry 4000&
    setenv CLASSPATH /u/data03/ic0fram
    java -Djava.rmi.server.codebase=file:///u/data03/ic0fram/ \
         -Djava.rmi.server.hostname=$HOST \
         prog3.AllPairsServer 4000
    
    Of course, you need to adjust the CLASSPATH, portnum, and codebase parameters for your own use. The books I've read all indicate using an http codebase, but there aren't any http servers running on the SP2 nodes.

  5. Of course you actually need to register several server objects on several different machines. You can do this by writing a 'start' script and using rsh. This is the start script that I used.
    #!/bin/csh
    unsetenv CLASSPATH
    rmiregistry 4000&
    setenv CLASSPATH /u/data03/ic0fram
    java -Djava.rmi.server.codebase=file:///u/data03/ic0fram/ \
         -Djava.rmi.server.hostname=$HOST \
         prog3.AllPairsServer 4000
    
    You can then use rsh to execute this on remote machines without logging in to all of them.
      rsh f01n09 /u/data03/ic0fram/remotestart
    

  6. Before you log out, you need to be nice and shut down all the things you left running on all the machines. You can also do this with rsh:
      rsh f01n09 killall
    
    Do be good about this.

  7. Now that you have the remote objects running, you need to write a main program to read the input file and activate the remote objects.
    import java.io.*;
    import java.rmi.Naming;
    import prog3.AllPairsInterface;
    
    class AllPairs {
    
      private static int               numberOfServers = 0;
      private static int               portNumber      = 4000;
      private static String            machineNames[];
      private static AllPairsInterface servers[];
    
      public static void main(String args[]) {
    
        String serverNames[] = new String[numberOfServers];
    
        //----------
        // connect to remote servers.
        //----------
        for (i = 0; i < numberOfServers; i++) {
          serverNames[i] = "rmi://" + machineNames[i] + ":" + portNumber +
                           "/AllPairsServer";
          System.out.println("Connecting to " + serverNames[i]);
          try { 
            servers[i] = (AllPairsInterface)Naming.lookup(serverNames[i]);
            System.out.println("Connected to " + servers[i].getHostName()); 
          } catch (Exception e) { 
            System.out.println("Exception: " + e.getMessage()); 
          }
        }
      }
    }
    


Exercise

As an exercise, write a solution to the previous program without using RMI. Create one thread per row and use a single monitor to synchronize the threads. You can then extend this program using RMI to distribute the threads for your final solution.

If you were asked this type of question on the final, you would only be required to write the monitor, not the threads or I/O.


Homework 2

The average was 89.

Report

Test Results

The five test cases were worth 12 points each
Deductions
ErrorPenalty
deadlock10
fails to terminate (deadlock after 60 seconds)3
neighbors eat simultaneously10
one or more philsophers starve8
no parallelism6
Test cases:
  1. five philosopher ring
     5 10 5
     0 1 0 0 1
     1 0 1 0 0
     0 1 0 1 0
     0 0 1 0 1
     1 0 0 1 0
    
  2. ten philosopher ring
     10 15 5
     0 1 0 0 0 0 0 0 0 1
     1 0 1 0 0 0 0 0 0 0
     0 1 0 1 0 0 0 0 0 0
     0 0 1 0 1 0 0 0 0 0
     0 0 0 1 0 1 0 0 0 0
     0 0 0 0 1 0 1 0 0 0
     0 0 0 0 0 1 0 1 0 0
     0 0 0 0 0 0 1 0 1 0
     0 0 0 0 0 0 0 1 0 1
     1 0 0 0 0 0 0 0 1 0
    
  3. six philosophers completely connected
     6 5 5
     0 1 1 1 1 1
     1 0 1 1 1 1
     1 1 0 1 1 1
     1 1 1 0 1 1
     1 1 1 1 0 1
     1 1 1 1 1 0
    
  4. thanksgiving dinner with a kids table, a dog, and a highchair
           2       6
          / \     / \
     0   1   3   5   7 - 9
          \ /     \ /
           4       8
    
     10 10 5
     0 0 0 0 0 0 0 0 0 0
     0 0 1 0 1 0 0 0 0 0
     0 1 0 1 0 0 0 0 0 0
     0 0 1 0 1 0 0 0 0 0
     0 1 0 1 0 0 0 0 0 0
     0 0 0 0 0 0 1 0 1 0
     0 0 0 0 0 1 0 1 0 0
     0 0 0 0 0 0 1 0 1 1
     0 0 0 0 0 1 0 1 0 0
     0 0 0 0 0 0 0 1 0 0
    
  5. six philosopher mess
     6 5 10
     0 1 1 0 1 0
     1 0 1 1 0 1
     1 1 0 1 1 0
     0 1 1 0 1 0
     1 0 1 1 0 1
     0 1 0 0 1 0
    

Style

General style things I look for are The guideline you should follow is that I should be able to read your code and figure out how it works without reading the comments.
Visual Correctness
Several things fell under "style" that are really correctness issues, but can only be discovered by reading the code. Most of these are places where I felt you could do things more efficiently. For example, it is inefficient to request one fork and wait for that fork before requesting others you need. (You will eat much faster if you request all your forks at once and receive them in any order.)

These are some of the deductions I made
Style Points
ItemDeduction
compiler warnings2
request forks one at a time5
request forks over and over3
modify shared variables in unsynchronized method5
failed to define DIRTY, CLEAN or use an enum type2
bad variable names1
missing function/entity comments (the comments make it easy for me to find the methods)1