import Utilities.*;

class Racer extends MyObject implements Runnable {

   private int M = 0;              // these fields are shared by both
   private volatile long sum = 0;  // threads since there is one object

   public Racer(String name, int M) {
      super(name);
      this.M = M;
      System.out.println("age()=" + age() + ", "
         + getName() + " is alive, M=" + M);
   }

   private long fn(long j, int k) {
      long total = j;
      for (int i = 1;  i <= k; i++) total += i;
      return total;
   }

   public void run() {
      System.out.println("age()=" + age() + ", "
         + getThreadName() + " is running");
      for (int m = 1; m <= M; m++)
/*
 * "N = N + 1" type lost update (race condition) in following line
 */
         sum = fn(sum, m);

      System.out.println("age()=" + age() + ", "
         + getThreadName() + " is done, sum = " + sum);
   }
}

class RaceTwoThreads extends MyObject {

   private static int M = 10;
   private final static int numRacers = 2;

   public static void main(String[] args) {

      // parse command line arguments, if any, to override defaults
      GetOpt go = new GetOpt(args, "UtSM:");
      go.optErr = true;
      String usage = "Usage: -t -S -M m";
      int ch = -1;
      boolean timeSlicingEnsured = false;
      boolean forceSequential = false;  // run the threads consecutively
      while ((ch = go.getopt()) != go.optEOF) {
         if      ((char)ch == 'U') {
            System.out.println(usage);  System.exit(0);
         }
         else if ((char)ch == 't') timeSlicingEnsured = true;
         else if ((char)ch == 'M')
            M = go.processArg(go.optArgGet(), M);
         else if ((char)ch == 'S') forceSequential = true;
         else {
            System.err.println(usage);  System.exit(1);
         }
      }
      System.out.println("RaceTwoThreads: M=" + M + ", timeSlicingEnsured="
         + timeSlicingEnsured + " forceSequential=" + forceSequential);

      // enable time slicing Solaris (50 msec); noop on Windows 95
      if (timeSlicingEnsured) ensureTimeSlicing(50); // so threads share CPU

      // start the two threads, both in the same object
      // so they share one instance of its variable sum
      Racer racerObject = new Racer("RacerObject", M);
      Thread[] racer = new Thread[numRacers];
      for (int i = 0; i < numRacers; i++)
         racer[i] = new Thread(racerObject, "RacerThread" + i);
      for (int i = 0; i < numRacers; i++) {
         racer[i].start();
         if (forceSequential)
            try {
               racer[i].join();  // wait for it to terminate
            } catch (InterruptedException e) {
               System.err.println("interrupted out of join");
            }     
      }
      System.out.println("age()=" + age() + ", all Racer threads started");

      // wait for them to finish if not forced consecutive
      if (!forceSequential)
         try {
            for (int i = 0; i < numRacers; i++) racer[i].join();
         } catch (InterruptedException e) {
            System.err.println("interrupted out of join");
         }

      // correct race-free final value of sum is 2*220 = 440 for M of 10
      // and 2*1335334000 = 2670668000 for M of 2000 (so `long sum' needed)
      System.out.println("RaceTwoThreads done");
      System.exit(0);
   }
}

/* ............... Example compile and run(s)

D:\>javac race.java

D:\>java RaceTwoThreads
Java version=1.1.1, Java vendor=Sun Microsystems Inc.
OS name=Windows 95, OS arch=x86, OS version=4.0
Wed Jul 02 16:59:16 EDT 1997
RaceTwoThreads: M=10, timeSlicingEnsured=false forceSequential=false
age()=60, RacerObject is alive, M=10
age()=60, all Racer threads started
age()=60, RacerThread0 is running
age()=60, RacerThread0 is done, sum = 220
age()=110, RacerThread1 is running
age()=110, RacerThread1 is done, sum = 440
RaceTwoThreads done

D:\>java RaceTwoThreads -M2000
RaceTwoThreads: M=2000, timeSlicingEnsured=false forceSequential=false
age()=50, RacerObject is alive, M=2000
age()=50, all Racer threads started
age()=50, RacerThread0 is running
age()=110, RacerThread1 is running
age()=2080, RacerThread0 is done, sum = 1335334000
age()=2080, RacerThread1 is done, sum = 1335345480
RaceTwoThreads done

D:\>java RaceTwoThreads -M2000 -S
RaceTwoThreads: M=2000, timeSlicingEnsured=false forceSequential=true
age()=0, RacerObject is alive, M=2000
age()=60, RacerThread0 is running
age()=1320, RacerThread0 is done, sum = 1335334000
age()=1380, RacerThread1 is running
age()=2360, RacerThread1 is done, sum = 2670668000
age()=2360, all Racer threads started
RaceTwoThreads done

% javac race.java

% java RaceTwoThreads -M2000
Java version=1.1_Final, Java vendor=Sun Microsystems Inc.
OS name=Solaris, OS arch=sparc, OS version=2.x
Tue Jul 01 13:56:15 PDT 1997
RaceTwoThreads: M=2000, timeSlicingEnsured=false forceSequential=false
age()=11, RacerObject is alive, M=2000
age()=14, all Racer threads started
age()=15, RacerThread0 is running
age()=1706, RacerThread0 is done, sum = 1335334000
age()=1708, RacerThread1 is running
age()=3409, RacerThread1 is done, sum = 2670668000

% java RaceTwoThreads -M2000 -t
RaceTwoThreads: M=2000, timeSlicingEnsured=true forceSequential=false
Scheduler: timeSlice=50 randomSlice=false priority=10
age()=35, RacerObject is alive, M=2000
age()=37, all Racer threads started
age()=38, RacerThread0 is running
age()=84, RacerThread1 is running
age()=3421, RacerThread0 is done, sum = 1335334000
age()=3456, RacerThread1 is done, sum = 1341543895
RaceTwoThreads done
                                            ... end of example run(s)  */
