Created
April 22, 2020 14:50
-
-
Save Aleksandar1932/1b0aa97471069642d0cf790d778467b0 to your computer and use it in GitHub Desktop.
syncHelperMethods
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package mk.ukim.finki.os.ispitni.syncHelperMethods; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* This class should be extended in order to preserve the state of the executing | |
* scenario | |
* | |
* @author ristes | |
* | |
*/ | |
public abstract class AbstractState { | |
/** | |
* Method called after threads ended their execution to validate the | |
* correctness of the scenario | |
*/ | |
public abstract void finalize(); | |
/** | |
* List of logged actions | |
*/ | |
private List<String> actions = new ArrayList<String>(); | |
/** | |
* | |
* @return if the current thread is instance of TemplateThread it is | |
* returned, and otherwise null is returned | |
*/ | |
protected TemplateThread getThread() { | |
Thread current = Thread.currentThread(); | |
if (current instanceof TemplateThread) { | |
TemplateThread t = (TemplateThread) current; | |
return t; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Log this exception or action | |
* | |
* @param e | |
* occurred exception (null if no exception) | |
* @param action | |
* Description of the occurring action | |
*/ | |
public synchronized void log(PointsException e, String action) { | |
TemplateThread t = (TemplateThread) Thread.currentThread(); | |
if (e != null) { | |
t.setException(e); | |
actions.add(t.toString() + "\t(e): " + e.getMessage()); | |
throw e; | |
} else if (action != null) { | |
actions.add(t.toString() + "\t(a): " + action); | |
} | |
} | |
/** | |
* Logging exceptions | |
* | |
* @param e | |
*/ | |
protected synchronized void logException(PointsException e) { | |
Thread t = Thread.currentThread(); | |
if (e != null) { | |
if (t instanceof TemplateThread) { | |
((TemplateThread) t).setException(e); | |
} | |
TemplateThread.hasException = true; | |
actions.add("\t(e): " + e.getMessage()); | |
throw e; | |
} | |
} | |
/** | |
* Printing of the actions and exceptions that has occurred | |
*/ | |
public synchronized void printLog() { | |
System.out | |
.println("Poradi konkurentnosta za pristap za pecatenje, mozno e nekoja od porakite da ne e na soodvetnoto mesto."); | |
System.out.println("Log na izvrsuvanje na akciite:"); | |
System.out.println("========================="); | |
System.out.println("tip\tid\titer\takcija/error"); | |
System.out.println("========================="); | |
for (String l : actions) { | |
System.out.println(l); | |
} | |
} | |
/** | |
* Prints the status of the execution, with the exceptions that has occur | |
*/ | |
public void printStatus() { | |
try { | |
finalize(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
if (!TemplateThread.hasException) { | |
int poeni = 25; | |
if (PointsException.getTotalPoints() == 0) { | |
System.out | |
.println("Procesot e uspesno sinhroniziran. Osvoeni 25 poeni."); | |
} else { | |
poeni -= PointsException.getTotalPoints(); | |
PointsException.printErrors(); | |
System.out.println("Maksimalni osvoeni poeni: " + poeni); | |
} | |
} else { | |
System.out | |
.println("Procesot ne e sinhroniziran spored uslovite na zadacata"); | |
printLog(); | |
System.out | |
.println("===================================================="); | |
PointsException.printErrors(); | |
int total = (25 - PointsException.getTotalPoints()); | |
if (total < 0) { | |
total = 0; | |
} | |
System.out.println("Maksimum Poeni: " + total); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package mk.ukim.finki.os.ispitni.syncHelperMethods; | |
/** | |
* This is helper class for incrementing and decrementing a integer variable, | |
* with range validation. It also checks for race condition occurrence if needed | |
* | |
* @author ristes | |
* | |
*/ | |
public class BoundCounterWithRaceConditionCheck { | |
private static final int RACE_CONDITION_POINTS = 25; | |
private static final String RACE_CONDITION_MESSAGE = "Race condition occured"; | |
private int value; | |
private Integer maxAllowed; | |
private Integer minAllowed; | |
private int maxErrorPoints; | |
private int minErrorPoints; | |
private String maxErrorMessage; | |
private String minErrorMessage; | |
public static int raceConditionDefaultTime = 3; | |
private int max; | |
/** | |
* | |
* @param value | |
*/ | |
public BoundCounterWithRaceConditionCheck(int value) { | |
super(); | |
this.value = value; | |
this.max = value; | |
} | |
/** | |
* | |
* @param value | |
* initial value | |
* @param maxAllowed | |
* upper bound of the value | |
* @param maxErrorPoints | |
* how many points are lost with the max value constraint | |
* violation | |
* @param maxErrorMessage | |
* message shown when the upper bound constrain is violated | |
* @param minAllowed | |
* lower bound of the value | |
* @param minErrorPoints | |
* how many points are lost with the min value constraint | |
* violation | |
* @param minErrorMessage | |
* message shown when the lower bound constrain is violated | |
*/ | |
public BoundCounterWithRaceConditionCheck(int value, Integer maxAllowed, | |
int maxErrorPoints, String maxErrorMessage, Integer minAllowed, | |
int minErrorPoints, String minErrorMessage) { | |
super(); | |
this.value = value; | |
this.max = value; | |
this.maxAllowed = maxAllowed; | |
this.minAllowed = minAllowed; | |
this.maxErrorPoints = maxErrorPoints; | |
this.minErrorPoints = minErrorPoints; | |
this.maxErrorMessage = maxErrorMessage; | |
this.minErrorMessage = minErrorMessage; | |
} | |
/** | |
* | |
* @return the maximum value of the integer variable that occurred at some | |
* point of the execution | |
*/ | |
public int getMax() { | |
return max; | |
} | |
/** | |
* | |
* @return the current value | |
*/ | |
public synchronized int getValue() { | |
return value; | |
} | |
public synchronized void setValue(int value) { | |
this.value = value; | |
} | |
/** | |
* Throws exception when the val is different than the value of the counter. | |
* | |
* @param val | |
* @param points | |
* @param errorMessage | |
* @return | |
*/ | |
public synchronized PointsException assertEquals(int val, int points, | |
String errorMessage) { | |
if (this.value != val) { | |
PointsException e = new PointsException(points, errorMessage); | |
return e; | |
} else { | |
return null; | |
} | |
} | |
public synchronized PointsException assertNotEquals(int val, int points, | |
String errorMessage) { | |
if (this.value == val) { | |
PointsException e = new PointsException(points, errorMessage); | |
return e; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Testing for race condition. NOTE: there are no guarantees that the race | |
* condition will be detected | |
* | |
* @return | |
*/ | |
public PointsException checkRaceCondition() { | |
return checkRaceCondition(raceConditionDefaultTime, | |
RACE_CONDITION_MESSAGE); | |
} | |
/** | |
* Testing for race condition. NOTE: there are no guarantees that the race | |
* condition will be detected, but higher the time argument is, the | |
* probability for race condition occurrence is higher | |
* | |
* @return | |
*/ | |
public PointsException checkRaceCondition(int time, String message) { | |
int val; | |
synchronized (this) { | |
val = value; | |
} | |
Switcher.forceSwitch(time); | |
if (val != value) { | |
PointsException e = new PointsException(RACE_CONDITION_POINTS, | |
message); | |
return e; | |
} | |
return null; | |
} | |
public PointsException incrementWithMax() { | |
return incrementWithMax(true); | |
} | |
public PointsException incrementWithMax(boolean checkRaceCondition) { | |
if (checkRaceCondition) { | |
PointsException raceCondition = checkRaceCondition(); | |
if (raceCondition != null) { | |
return raceCondition; | |
} | |
} | |
synchronized (this) { | |
value++; | |
if (value > max) { | |
max = value; | |
} | |
if (maxAllowed != null) { | |
if (value > maxAllowed) { | |
PointsException e = new PointsException(maxErrorPoints, | |
maxErrorMessage); | |
return e; | |
} | |
} | |
} | |
return null; | |
} | |
public PointsException decrementWithMin() { | |
return decrementWithMin(true); | |
} | |
public PointsException decrementWithMin(boolean checkRaceCondition) { | |
if (checkRaceCondition) { | |
PointsException raceCondition = checkRaceCondition(); | |
if (raceCondition != null) { | |
return raceCondition; | |
} | |
} | |
synchronized (this) { | |
value--; | |
if (minAllowed != null) { | |
if (value < minAllowed) { | |
PointsException e = new PointsException(minErrorPoints, | |
minErrorMessage); | |
return e; | |
} | |
} | |
} | |
return null; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package mk.ukim.finki.os.ispitni.syncHelperMethods; | |
import java.util.HashMap; | |
import java.util.Map; | |
public class PointsException extends RuntimeException { | |
private static HashMap<String, PointsException> exceptions = new HashMap<String, PointsException>(); | |
private int points; | |
public PointsException(int points, String message) { | |
super(message); | |
this.points = points; | |
exceptions.put(message, this); | |
} | |
public static int getTotalPoints() { | |
int sum = 0; | |
for (PointsException e : exceptions.values()) { | |
sum += e.getPoints(); | |
} | |
return sum; | |
} | |
public static void printErrors() { | |
if (!exceptions.isEmpty()) { | |
System.out.println("Gi imate slednite greski: "); | |
for (Map.Entry<String, PointsException> e : exceptions.entrySet()) { | |
System.out.println(String.format("[%s] : (-%d)", e.getKey(), e | |
.getValue().getPoints())); | |
} | |
} | |
} | |
public int getPoints() { | |
return points; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package mk.ukim.finki.os.ispitni.syncHelperMethods; | |
import java.util.HashSet; | |
public abstract class ProblemExecution { | |
public static void start(HashSet<Thread> threads, AbstractState state) | |
throws Exception { | |
startWithoutDeadlock(threads, state); | |
checkDeadlock(threads, state); | |
} | |
public static void startWithoutDeadlock(HashSet<Thread> threads, | |
AbstractState state) throws Exception { | |
// start the threads | |
for (Thread t : threads) { | |
t.start(); | |
} | |
// wait threads to finish | |
for (Thread t : threads) { | |
t.join(1000); | |
} | |
} | |
private static void checkDeadlock(HashSet<Thread> threads, | |
AbstractState state) { | |
// check for deadlock | |
for (Thread t : threads) { | |
if (t.isAlive()) { | |
t.interrupt(); | |
if (t instanceof TemplateThread) { | |
TemplateThread tt = (TemplateThread) t; | |
tt.setException(new PointsException(25, "DEADLOCK")); | |
} | |
} | |
} | |
// print the status | |
state.printStatus(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package mk.ukim.finki.os.ispitni.syncHelperMethods; | |
import java.util.Random; | |
public class Switcher { | |
private static final Random RANDOM = new Random(); | |
/* | |
* This method pauses the current thread i.e. changes its state to be | |
* Blocked. This should force thread switch if there are threads waiting | |
*/ | |
public static void forceSwitch(int range) { | |
try { | |
Thread.sleep(RANDOM.nextInt(range)); | |
} catch (InterruptedException e) { | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package mk.ukim.finki.os.ispitni.syncHelperMethods; | |
import java.util.Date; | |
public abstract class TemplateThread extends Thread { | |
static boolean hasException = false; | |
public int iteration = 0; | |
protected Exception exception = null; | |
int numRuns = 1; | |
public TemplateThread(int numRuns) { | |
this.numRuns = numRuns; | |
} | |
public abstract void execute() throws InterruptedException; | |
@Override | |
public void run() { | |
try { | |
for (int i = 0; i < numRuns && !hasException; i++) { | |
execute(); | |
iteration++; | |
} | |
} catch (InterruptedException e) { | |
// Do nothing | |
} catch (Exception e) { | |
exception = e; | |
e.printStackTrace(); | |
hasException = true; | |
} | |
} | |
public void setException(Exception exception) { | |
this.exception = exception; | |
hasException = true; | |
} | |
@Override | |
public String toString() { | |
Thread current = Thread.currentThread(); | |
if (numRuns > 1) { | |
return String.format("[%d]%s\t%d\t%d", new Date().getTime(), "" | |
+ current.getClass().getSimpleName().charAt(0), getId(), | |
iteration); | |
} else { | |
return String.format("[%d]%s\t%d\t", new Date().getTime(), "" | |
+ current.getClass().getSimpleName().charAt(0), getId()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment