Help with Operating Systems Theory (CPU Scheduling, and Java Synchronization using monitors)
engineeroc346_pa3_w12.zip
C346_PA3_W12/src/common/BaseThread.java
C346_PA3_W12/src/common/BaseThread.java
package
common
;
import
java
.
util
.
Random
;
/**
* Class BaseThread
* Simply one customized base class for many of our own threads
*
* An attempt to maintain an automatic unique TID (thread ID)
* among all the derivatives and allow setting your own if needed.
* Plus some methods for the sync exercises.
*
* $Revision: 1.2 $
* $Last Revision Date: 2010/10/24 $
*
*
@author
Serguei A. Mokhov, mokhov
@cs
.concordia.ca
*/
public
class
BaseThread
extends
Thread
{
/*
* ------------
* Data members
* ------------
*/
/**
* Preserves value across all instances
*/
public
static
int
siNextTID
=
1
;
/**
* Our Thread ID
*/
protected
int
iTID
;
/**
* TID of a thread to proceed to the phase II
*/
private
static
int
siTurn
=
1
;
/*
* ------------
* Constructors
* ------------
*/
/**
* Default
*/
public
BaseThread
()
{
setTID
();
}
/**
* Assigns name to the thread and places it to the specified group
*
*
@param
poGroup ThreadGroup to add this thread to
*
@param
pstrName A string indicating human-readable thread's name
*/
public
BaseThread
(
ThreadGroup
poGroup
,
String
pstrName
)
{
super
(
poGroup
,
pstrName
);
setTID
();
}
/**
* Sets user-specified TID
*/
public
BaseThread
(
final
int
piTID
)
{
this
.
iTID
=
piTID
;
}
/**
* Retrieves our TID
*
@return
TID, integer
*/
public
final
int
getTID
()
{
return
this
.
iTID
;
}
/**
* Sets internal TID and updates next TID on contruction time, so it's private.
*/
private
final
void
setTID
()
{
this
.
iTID
=
siNextTID
++
;
}
/**
* Just a make up for the PHASE I to make it somewhat tangeable.
* Must be atomic.
*/
protected
synchronized
void
phase1
()
{
System
.
out
.
println
(
this
.
getClass
().
getName
()
+
" thread [TID="
+
this
.
iTID
+
"] starts PHASE I."
);
System
.
out
.
println
(
"Some stats info in the PHASE I:\n"
+
" iTID = "
+
this
.
iTID
+
", siNextTID = "
+
siNextTID
+
", siTurn = "
+
siTurn
+
".\n Their \"checksum\": "
+
(
siNextTID
*
100
+
this
.
iTID
*
10
+
siTurn
)
);
System
.
out
.
println
(
this
.
getClass
().
getName
()
+
" thread [TID="
+
this
.
iTID
+
"] finishes PHASE I."
);
}
/**
* Just a make up for the PHASE II to make it somewhat tangeable.
* Must be atomic.
*/
protected
synchronized
void
phase2
()
{
System
.
out
.
println
(
this
.
getClass
().
getName
()
+
" thread [TID="
+
this
.
iTID
+
"] starts PHASE II."
);
System
.
out
.
println
(
"Some stats info in the PHASE II:\n"
+
" iTID = "
+
this
.
iTID
+
", siNextTID = "
+
siNextTID
+
", siTurn = "
+
siTurn
+
".\n Their \"checksum\": "
+
(
siNextTID
*
100
+
this
.
iTID
*
10
+
siTurn
)
);
System
.
out
.
println
(
this
.
getClass
().
getName
()
+
" thread [TID="
+
this
.
iTID
+
"] finishes PHASE II."
);
}
/**
* Test-and-Set for the iTurn variable.
*
* Use to proceed to the phase II in the correct order.
* Must be atomic.
*
*
@param
pcIncreasingOrder true if TIDs are in increasing order; false otherwise
*
*
@return
Returns true if if the TID of currently running thread matches the turn, 'false' otherwise
*/
public
synchronized
boolean
turnTestAndSet
(
boolean
pcIncreasingOrder
)
{
// test
if
(
siTurn
==
this
.
iTID
)
{
// set siTurn = siTurn +/- 1;
if
(
pcIncreasingOrder
==
true
)
siTurn
++
;
else
siTurn
--
;
return
true
;
}
return
false
;
}
/**
* Always assumes the increasing order
*/
public
synchronized
boolean
turnTestAndSet
()
{
return
turnTestAndSet
(
true
);
}
/**
* Allows setting arbitratu turn value. Should be set only before
* the threads are started
*/
public
static
void
setInitialTurn
(
int
piTurn
)
{
siTurn
=
piTurn
;
}
/**
* Default ascending order
*/
public
static
void
setInitialTurnAscending
()
{
setInitialTurn
(
1
);
}
/**
* Descending order
*/
public
static
void
setInitialTurnDescending
()
{
setInitialTurn
(
siNextTID
-
1
);
}
/**
* Calls yield() several (4-40, pseudorandomly) times.
* Next to useless, but helps to mix up the execution of phases.
* Must NOT be atomic.
*/
public
void
randomYield
()
{
// Generate from 5 to 40 yield()'s pseudorandomly
int
iNumYields
=
(
int
)((
new
Random
()).
nextFloat
()
*
35
)
+
5
;
for
(
int
i
=
0
;
i
<
iNumYields
;
i
++
)
yield
();
}
}
// EOF
C346_PA3_W12/src/DiningPhilosophers.java
C346_PA3_W12/src/DiningPhilosophers.java
/**
* Class DiningPhilosophers
* The main starter.
*
*
@author
Serguei A. Mokhov, mokhov
@cs
.concordia.ca
*/
public
class
DiningPhilosophers
{
/*
* ------------
* Data members
* ------------
*/
/**
* This default may be overridden from the command line
*/
public
static
final
int
DEFAULT_NUMBER_OF_PHILOSOPHERS
=
4
;
/**
* Dining "iterations" per philosopher thread
* while they are socializing there
*/
public
static
final
int
DINING_STEPS
=
10
;
/**
* Our shared monitor for the philosphers to consult
*/
public
static
Monitor
soMonitor
=
null
;
/*
* -------
* Methods
* -------
*/
/**
* Main system starts up right here
*/
public
static
void
main
(
String
[]
argv
)
{
try
{
/*
* TODO:
* Should be settable from the command line
* or the default if no arguments supplied.
*/
int
iPhilosophers
=
DEFAULT_NUMBER_OF_PHILOSOPHERS
;
// Make the monitor aware of how many philosophers there are
soMonitor
=
new
Monitor
(
iPhilosophers
);
// Space for all the philosophers
Philosopher
aoPhilosophers
[]
=
new
Philosopher
[
iPhilosophers
];
// Let 'em sit down
for
(
int
j
=
0
;
j
<
iPhilosophers
;
j
++
)
{
aoPhilosophers
[
j
]
=
new
Philosopher
();
aoPhilosophers
[
j
].
start
();
}
System
.
out
.
println
(
iPhilosophers
+
" philosopher(s) came in for a dinner."
);
// Main waits for all its children to die...
// I mean, philosophers to finish their dinner.
for
(
int
j
=
0
;
j
<
iPhilosophers
;
j
++
)
aoPhilosophers
[
j
].
join
();
System
.
out
.
println
(
"All philosophers have left. System terminates normally."
);
}
catch
(
InterruptedException
e
)
{
System
.
err
.
println
(
"main():"
);
reportException
(
e
);
System
.
exit
(
1
);
}
}
// main()
/**
* Outputs exception information to STDERR
*
@param
poException Exception object to dump to STDERR
*/
public
static
void
reportException
(
Exception
poException
)
{
System
.
err
.
println
(
"Caught exception : "
+
poException
.
getClass
().
getName
());
System
.
err
.
println
(
"Message : "
+
poException
.
getMessage
());
System
.
err
.
println
(
"Stack Trace : "
);
poException
.
printStackTrace
(
System
.
err
);
}
}
// EOF
C346_PA3_W12/src/Makefile
# Just a makefile to save some typing :-) # Serguei A. Mokhov, [email protected] # PA3 # Use gmake. JAVAC=javac JFLAGS=-g JVM=java EXE=DiningPhilosophers ASMTDIRS := . common # Lists of all *.java and *.class files JAVAFILES := $(ASMTDIRS:%=%/*.java) CLASSES := $(ASMTDIRS:%=%/*.class) all: $(EXE).class @echo "Dining Philosophers Application has been built." $(EXE).class: $(JAVAFILES) $(JAVAC) $(JFLAGS) $(EXE).java run: all $(JVM) $(EXE) regression: all @for arg in 3 4 5; do $(JVM) $(EXE) $$arg; done clean: rm -f $(CLASSES) #* *~ # EOF
C346_PA3_W12/src/Monitor.java
C346_PA3_W12/src/Monitor.java
/**
* Class Monitor
* To synchronize dining philosophers.
*
*
@author
Serguei A. Mokhov, mokhov
@cs
.concordia.ca
*/
public
class
Monitor
{
/*
* ------------
* Data members
* ------------
*/
/**
* Constructor
*/
public
Monitor
(
int
piNumberOfPhilosophers
)
{
// TODO: set appropriate number of chopsticks based on the # of philosophers
}
/*
* -------------------------------
* User-defined monitor procedures
* -------------------------------
*/
/**
* Grants request (returns) to eat when both chopsticks/forks are available.
* Else forces the philosopher to wait()
*/
public
synchronized
void
pickUp
(
final
int
piTID
)
{
// ...
}
/**
* When a given philosopher's done eating, they put the chopstiks/forks down
* and let others know they are available.
*/
public
synchronized
void
putDown
(
final
int
piTID
)
{
// ...
}
/**
* Only one philopher at a time is allowed to philosophy
* (while she is not eating).
*/
public
synchronized
void
requestTalk
()
{
// ...
}
/**
* When one philosopher is done talking stuff, others
* can feel free to start talking.
*/
public
synchronized
void
endTalk
()
{
// ...
}
}
// EOF
C346_PA3_W12/src/Philosopher.java
C346_PA3_W12/src/Philosopher.java
import
common
.
BaseThread
;
/**
* Class Philosopher.
* Outlines main subrutines of our virtual philosopher.
*
*
@author
Serguei A. Mokhov, mokhov
@cs
.concordia.ca
*/
public
class
Philosopher
extends
BaseThread
{
/**
* Max time an action can take (in milliseconds)
*/
public
static
final
long
TIME_TO_WASTE
=
1000
;
/**
* The act of eating.
* - Print the fact that a given phil (their TID) has started eating.
* - Then sleep() for a random interval.
* - The print that they are done eating.
*/
public
void
eat
()
{
try
{
// ...
sleep
((
long
)(
Math
.
random
()
*
TIME_TO_WASTE
));
// ...
}
catch
(
InterruptedException
e
)
{
System
.
err
.
println
(
"Philosopher.eat():"
);
DiningPhilosophers
.
reportException
(
e
);
System
.
exit
(
1
);
}
}
/**
* The act of thinking.
* - Print the fact that a given phil (their TID) has started thinking.
* - Then sleep() for a random interval.
* - The print that they are done thinking.
*/
public
void
think
()
{
// ...
}
/**
* The act of talking.
* - Print the fact that a given phil (their TID) has started talking.
* - Say something brilliant at random
* - The print that they are done talking.
*/
public
void
talk
()
{
// ...
saySomething
();
// ...
}
/**
* No, this is not the act of running, just the overridden Thread.run()
*/
public
void
run
()
{
for
(
int
i
=
0
;
i
<
DiningPhilosophers
.
DINING_STEPS
;
i
++
)
{
DiningPhilosophers
.
soMonitor
.
pickUp
(
getTID
());
eat
();
DiningPhilosophers
.
soMonitor
.
putDown
(
getTID
());
think
();
/*
* TODO:
* A decision is made at random whether this particular
* philosopher is about to say something terribly useful.
*/
if
(
true
==
false
)
{
// Some monitor ops down here...
talk
();
// ...
}
}
}
// run()
/**
* Prints out a phrase from the array of phrases at random.
* Feel free to add your own phrases.
*/
public
void
saySomething
()
{
String
[]
astrPhrases
=
{
"Eh, it's not easy to be a philosopher: eat, think, talk, eat..."
,
"You know, true is false and false is true if you think of it"
,
"2 + 2 = 5 for extremely large values of 2..."
,
"If thee cannot speak, thee must be silent"
,
"My number is "
+
getTID
()
+
""
};
System
.
out
.
println
(
"Philosopher "
+
getTID
()
+
" says: "
+
astrPhrases
[(
int
)(
Math
.
random
()
*
astrPhrases
.
length
)]
);
}
}
// EOF