I have created three threads in a java program. One is the main program, the others are two classes that extend Thread. The main thread represent a controller for a machine. Another thread is the actuators and the third is the sensors. The controller sets variables in its own class which is read by the actuator thread. The actuator performs certain actions according to the instructions and update its own internal variables. These are in turn read by the sensor thread which reads the actuator variables (representing real world actions) and sets its own internal variables which in turn is read by the controller and we have come full circle. The controller then sets variables according to the new sensed world etc.
The actuators are in a eternal loop sleeping 100 ms in each loop.
The sensors are also in an eternal loop sleeping 20ms per loop.
The system almost works. The main loop will miss the updates from the sensor unless I add a sleep to it as well. My question is now why that is? Even sleep(0) makes the system work. I've placed the statement inside the performJob(Job input) while loop. How does the java main thread without a sleep call act differently than the same thread with?
Concurrency is a fairly new subject to me.
This is the code I am using:
Main:
public class Main {
public static void main(String[] args) {
Controller Press = new Controller();
Press.processUnits(1); // no reset code at the moment, only use 1 at a time
Press.shutdownThreads();
}
}
Controller:
import java.util.LinkedList;
public class Controller extends Thread {
// Constants
static final int STATE_WAITING = 0;
static final int STATE_MOVE_ARMS = 1;
static final int STATE_MOVE_PRESS = 2;
static final int LOADINGARM = 2;
static final int UNLOADINGARM = 1;
static final int NOARM = 0;
static final boolean EXTEND = true;
static final boolean RETRACT = false;
private enum Jobs {
EXTENDRETRACT, ROTATE, MAGNETONOFF, PRESSLOWERRAISE
}
// Class variables
private int currentState;
// Component instructions
private int armChoice = 0;
private boolean bool = false; // on, up, extend / off, down, retract
private boolean[] rotInstr = {false, false}; // {rotate?, left true/right false}
private boolean errorHasOccurred = false;
private boolean pressDir = false;
private Sensors sense = null;
private Actuators act = null;
private LinkedList<Job> queue = null;
// Constructor
public Controller() {
act = new Actuators(0.0f, this);
sense = new Sensors();
act.start();
sense.start();
currentState = STATE_WAITING;
queue = new LinkedList<Job>();
}
// Methods
int[] getArmInstructions() {
int extret = (bool) ? 1 : 0;
int[] ret = {armChoice, extret};
return ret;
}
boolean[] getRotation() {
return rotInstr;
}
int getControllerState() {
return currentState;
}
boolean getPressDirection() {
return pressDir;
}
public boolean processUnits(int nAmount) {
if (run(nAmount)) {
System.out.println("Controller: All units have been processed successfully.");
return true;
} else { // procUnits returning false means something went wrong
System.out.println("Controller: An error has occured. The process cannot complete.");
return false;
}
}
/*
* This is the main run routine. Here the controller analyses its internal state and its sensors
* to determine what is happening. To control the arms and press, it sets variables, these symbolize
* the instructions that are sent to the actuators. The actuators run in a separate thread which constantly
* reads instructions from the controller and act accordingly. The sensors and actuators are dumb, they
* will only do what they are told, and if they malfunction it is up to the controller to detect dangers or
* malfunctions and either abort or correct.
*/
private boolean run(int nUnits) {
/*
Here depending on internal state, different actions will take place. The process uses a queue of jobs
to keep track of what to do, it reads a job, sets the variables and then waits until that job has finished
according to the sensors, it will listen to all the sensors to make sure the correct sequence of events is
taking place. The controller reads the sensor information from the sensor thread which runs on its own
similar to the controller.
In state waiting the controller is waiting for input, when given the thread cues up the appropriate sequence of jobs
and changes its internal state to state move arms
In Move arms, the controller is actively updating its variables as its jobs are performed,
In this state the jobs are, extend, retract and rotate, pickup and drop.
From this state it is possible to go to move press state once certain conditions apply
In Move Press state, the controller through its variables control the press, the arms must be out of the way!
In this state the jobs are press goes up or down. Pressing is taking place at the topmost position, middle position is for drop off
and lower is for pickup. When the press is considered done, the state reverts to move arms,
*/
//PSEUDO CODE:
//This routine being called means that there are units to be processed
//Make sure the controller is not in a blocking state, that is, it shut down previously due to errors
//dangers or malfunctions
//If all ok - ASSUMED SO AS COMPONENTS ARE FAULT FREE IN THIS VERSION
if (!errorHasOccurred) {
//retract arms
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//System.out.println("Jobs added");
//while there are still units to process
for (;nUnits != 0; nUnits--) {
//move the press to lower position, for unloading
currentState = STATE_MOVE_PRESS;
//rotate to pickup area and pickup the metal, also pickup processed
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, EXTEND));
performWork();
//retract and rotate
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//state change, press moves to middle position
currentState = STATE_MOVE_PRESS;
//state change back, put the metal on the press, drop processed and pull arms back
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//state change, press the metal in upper position
currentState = STATE_MOVE_PRESS;
//repeat until done
}
//unload final piece
//move the press to lower position for unload
//rotate and pickup processed piece
//drop it off at unloading and wait for more orders
currentState = STATE_WAITING;
}
return true;
}
private boolean performWork() {
while (!queue.isEmpty()) {
performJob(queue.removeFirst());
}
return true;
}
private boolean performJob(Job input) {
//The purpose of this function is to update the variables and wait until they are completed
// read in the job and check appropriate sensors
boolean[] data = sense.getSensorData(); // LExt, LRet, UlExt, UlRet
printBools(data);
int Instruction = input.Instruction;
boolean skipVars = false;
if (input.Job == Jobs.EXTENDRETRACT) {
if (currentState != STATE_MOVE_ARMS){
System.out.println("Wrong state in performJob. State is "+currentState+" expected "+STATE_MOVE_ARMS);
return false;
}
if ((Instruction == LOADINGARM) && (input.Bool)) skipVars = data[0];
if ((Instruction == LOADINGARM) && (!input.Bool)) skipVars = data[1];
if ((Instruction == UNLOADINGARM) && (input.Bool)) skipVars = data[2];
if ((Instruction == UNLOADINGARM) && (!input.Bool)) skipVars = data[3];
}
if (!skipVars) {
// if sensors not at intended values, update correct variables
System.out.println("Controller: Did not skip vars");
switch (input.Job) {
case EXTENDRETRACT:
armChoice = (Instruction == LOADINGARM) ? LOADINGARM : UNLOADINGARM;
bool = input.Bool;
break;
case ROTATE:
break;
case MAGNETONOFF:
break;
case PRESSLOWERRAISE:
break;
default:
System.out.println("Default called in performJob()");
break;
}
}
// listen to sensors until completed
boolean done = false;
System.out.println("Waiting for sensor data.");
//System.out.print("Instruction is "+Instruction+" and bool is "); if (input.Bool) System.out.print("true\n"); else System.out.print("false\n");
while (!done) {
data = sense.getSensorData();
// REMOVING THIS TRY STATEMENT BREAKS THE PROGRAM
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
System.out.println("Main thread couldn't sleep.");
}
// Check appropriate sensors
if (input.Job == Jobs.EXTENDRETRACT) {
if ((Instruction == LOADINGARM) && (input.Bool)) done = data[0];
if ((Instruction == LOADINGARM) && (!input.Bool)) done = data[1];
if ((Instruction == UNLOADINGARM) && (input.Bool)) done = data[2];
if ((Instruction == UNLOADINGARM) && (!input.Bool)) done = data[3];
}
}
// reset all variables
armChoice = 0;
bool = false;
// when done return
System.out.println("Finished "+input.Job);
return true;
}
public void shutdownThreads() {
sense.shutDown();
act.shutDown();
}
private class Job {
// Class variables
Jobs Job;
int Instruction;
boolean Bool; // used for directions, up/down, left/right, extend/retract
// Constructor
Job(Jobs newJob, int newInstruction, boolean dir) {
Job = newJob;
Instruction = newInstruction;
Bool = dir;
}
}
private void printBools(boolean[] input) {
System.out.println();
for (int i = 0; i < input.length; i++) {
if (input[i]) System.out.print("true "); else System.out.print("false ");
}
System.out.println();
}
}
Actuators:
public class Actuators extends Thread {
// Constants
private final int ARM = 0, ROTATE = 0; // array indexes - which arm, rotate yes/no?
private final int DIR = 1, ROTDIR = 1; // array indexes - which direction ext/ret, rotate direction
private final int EXT = 1;//, RET = 0;
private final double ARM_SPEED = 5.0;
// Class variables
private Controller Owner = null;
private boolean run = true;
// Constructor
Actuators(float nPos, Controller Owner) {
Reality.changeAngle(nPos);
this.Owner = Owner;
}
// Methods
private void rotate(boolean dir) {
float nAngle = dir ? 0.1f : -0.1f;
Reality.changeAngle(nAngle);
}
public void run() {
while (run) {
try {
sleep(100);
} catch (InterruptedException e) {
System.out.println("Actuators couldn't sleep");
}
// read variables in controller
int nState = Owner.getControllerState();
if (nState == Controller.STATE_MOVE_ARMS) {
boolean[] rot = Owner.getRotation();
if (rot[ROTATE]) { // Rotation?
rotate(rot[ROTDIR]);
} else { // or arm extensions
int[] instr = Owner.getArmInstructions();
if (instr[ARM] != Controller.NOARM) { // 0 = no arm movement
//System.out.println("Actuator arm is "+instr[ARM]);
double dir = (instr[DIR] == EXT) ? ARM_SPEED : -ARM_SPEED; // 1 = extend, 0 = retract
Reality.changeArmLength(instr[ARM], dir);
}
}
}
}
}
void shutDown() {
run = false;
}
}
Reality is a class composed of static fields and methods, written to by the actuators and read by sensors.
public class Reality {
// Constants
static private final double EXTEND_LIMIT = 100.0;
static private final double RETRACT_LIMIT = 0.0;
// Variables
private static float ArmsAngle = 0.0f;
// Read by Sensor
static double LoadingArmPos = 0.0;
static double UnloadingArmPos = 0.0;
// Methods
static void changeAngle(float newAngle) {
ArmsAngle = ArmsAngle + newAngle;
if ((ArmsAngle < 0.0f) || (ArmsAngle > 90.0f))
System.out.println("Reality: Unallowed Angle");
}
static void changeArmLength(int nArm, double dPos) { // true = extend, false = retract
switch (nArm) {
case Controller.LOADINGARM:
LoadingArmPos += dPos;
checkArmPos(LoadingArmPos);
break;
case Controller.UNLOADINGARM:
UnloadingArmPos += dPos;
checkArmPos(UnloadingArmPos);
break;
default:
System.out.println("Arm other than 2 (load) or 1 (unload) in changeArmLength in Reality");
break;
}
}
static float senseAngle() {
return ArmsAngle;
}
static private boolean checkArmPos(double dPos) {
// Allowed positions are 100.0 to 0.0
if ((dPos > EXTEND_LIMIT) || (dPos < RETRACT_LIMIT)) {
System.out.println("Arm position impossible in reality. Is "+dPos);
return true;
} else {
return false;
}
}
}
Finally the sensors:
public class Sensors extends Thread {
// Constants
private final double EXTENDED = 100.0;
private final double RETRACTED = 0.0;
private final double MARGIN = 0.1;
// Class Variables
private boolean run = true;
// Read by Controller
private boolean LoadingExtended = true;
private boolean LoadingRetracted = true;
private boolean UnloadingExtended = true;
private boolean UnloadingRetracted = true;
// Constructor
Sensors() {
LoadingExtended = false;
LoadingRetracted = true;
UnloadingExtended = false;
UnloadingRetracted = true;
}
// Methods
boolean senseLoadingExtended() {
return (Math.abs(Reality.LoadingArmPos - EXTENDED) < MARGIN);
}
boolean senseLoadingRetracted() {
return (Math.abs(Reality.LoadingArmPos - RETRACTED) < MARGIN);
}
boolean senseUnloadingExtended() {
return (Math.abs(Reality.UnloadingArmPos - EXTENDED) < MARGIN);
}
boolean senseUnloadingRetracted() {
return (Math.abs(Reality.UnloadingArmPos - RETRACTED) < MARGIN);
}
// called by Controller
boolean[] getSensorData() {
boolean[] ret = {LoadingExtended, LoadingRetracted, UnloadingExtended, UnloadingRetracted};
return ret;
}
// Sensor primary loop
public void run() {
while (run) {
try {
sleep(20);
}
catch (InterruptedException e) {
System.out.println("Sensors couldn't sleep");
}
LoadingExtended = senseLoadingExtended();
LoadingRetracted = senseLoadingRetracted();
UnloadingExtended = senseUnloadingExtended();
UnloadingRetracted = senseUnloadingRetracted();
}
}
void shutDown() {
run = false;
}
}
Not all fields and functions are read in this version. The program is a reworking of a previous single thread application mostly using function calls. I've cleaned up the code a bit for readability. Constructive design remarks are welcome even though it was not the original question. There is something really fishy going on. I am usually not a superstitious coder but I can for example replace the sleep call with a System.out.println() call and the program will work.
Google for 'Producer consumer queue'.
Don't use sleep() for inter-thread comms unless you want latency, inefficiency and lost data. There are much better mechanisms available that avoid sleep() and trying to read valid data directly from some shared/locked object.
If you load up 'comms' objects with commands/requests/data, queue them off to other threads and immediately create another comms object for subsequent communication, your inter-thread comms will be fast and safe, no sleep() latency and no chance of any thread reading data that is stale or being changed by another thread.
What occurred here was most probably a Memory Consistency Error. When the controller class set the internal control variables and then entered the loop waiting for sensors it most likely prevented the Actuators and Sensors classes from properly updating the readings seen to the controller and as such prevented the controller from seeing the correct values. By adding the synchronize statement to all functions which read from another class the problem was solved. I can only speculate that the sleep call had the controller thread enter a synchronized block of some kind which let the other threads' changes to the variables become visible.
Which JVM are you using?
As fast workaround you can set volatile for fields that shared between threads.
Also please look to actors' approach for messaging: http://doc.akka.io/docs/akka/snapshot/java/untyped-actors.html
Related
I'm having an issue and I'm not certain if it's recursion-based. I created a GUI maze that solves itself but the curser jumps over any recursion-traveled square instead of re-traveling the square. Even though it ultimately finds the goal, I want to show it's entire path but I can't stop the curser from jumping around.
I'm using Runnable to track the maze in real-time so I can see it bounce but without the recursion-travel keeping it bound, the recursive functions cease to work (it just bounces back and forth which, again, I don't quite understand.) I started java about three months ago in an accelerated program so I'm not sure if the issue is my understanding of recursion, or a simple addition to a method, or if I'll have to rewrite a large portion of code.
I included the whole code just in case but really it's an issue that's within the travel method or the visited method. Would the answer be to write an entirely new method that re-travels the changed "visited" string maze? I've been struggling with this for a bit and I just need some direction toward an answer.
import java.awt.*;
import javax.swing.*;
class extraCreditMaze extends JPanel implements Runnable { //uses Runnable to execute jPanel
private String [][] ratMaze = //string maze
{{"blocked","blocked","blocked","blocked","blocked","blocked","blocked","blocked"},
{"blocked","open","blocked","blocked","blocked","blocked","blocked","blocked"},
{"blocked","open","open","open","open","open","open","blocked"},
{"blocked","blocked","open","blocked","open","blocked","open","blocked"},
{"blocked","blocked","open","blocked","open","blocked","open","goal"},
{"blocked","open","open","open","blocked","open","open","blocked"},
{"blocked","blocked","blocked","open","open","open","blocked","blocked"},
{"blocked","blocked","blocked","blocked","blocked","blocked","blocked","blocked"}};
final private int SquareSize = 15;
final private int BoardSize = 17;
private boolean free = false;
int axisX = 1, axisY = 1;
public void paintComponent(Graphics color) //paint components for char
{
super.paintComponent(color);
for(int row = 0; row < ratMaze.length; row++)
{
for(int col = 0; col< ratMaze.length; col++)
{
if(row==axisX && col==axisY) //traveling curser = blue
{
color.setColor(Color.blue);
color.fillOval(col*15,row*15,15,15);
}
else if(ratMaze[row][col]=="blocked") //empty = black
{
color.setColor(Color.black);
color.fillRect(col*SquareSize,row*SquareSize,BoardSize,BoardSize);
}
else if(ratMaze[row][col]=="goal")
{
color.setColor(Color.red); //goal = red
color.fillOval(col*15,row*15,15,15);
}
else if(ratMaze[row][col]=="visited")
{
color.setColor(Color.green); //path traveled = green
color.fillOval(col*15,row*15,15,15);
}
else
{
color.setColor(Color.white); //empty space = white
color.fillRect(col*SquareSize,row*SquareSize,BoardSize,BoardSize);
}
}
}
}
public void run () //starts run at (1,1)
{
travel(1,1);
}
public boolean goal(int x, int y){ //method to check goal (true/false)
if(ratMaze[x][y]=="goal")
return true;
else
return false;
}
public void changedVisited(int x, int y) //method to change traveled
{
ratMaze[x][y] = "visited";
axisX = x;
axisY = y;
}
public boolean boundaries(int x, int y) //check boundaries
{
if(ratMaze[x][y]=="blocked")
return true;
else
return false;
}
public boolean visited(int x, int y) //check if visited
{
if(ratMaze[x][y]=="visited")
return true;
else
return false;
}
private void travel(int x, int y)
{
if(boundaries(x,y)) //makes sure it's within bounds
return;
if(visited(x,y)) //makes sure it hasn't already been visited
return;
if(goal(x,y)) //checks if it's the goal/changes boolean
{
free = true;
JOptionPane.showMessageDialog(this, "You did it, Dr. Cui!"); //fun message!
}
if(!free) //all recursion functions if free=false
{
changedVisited(x,y); //changes traveled block to "visited"
repaint(); //repaints visited
try {Thread.sleep(300); } catch (Exception e) { }//slows down the traveling curser
//I do not understand catch (Exception e)
travel(x-1,y); //recursive travel functions
travel(x+1,y);
travel(x,y-1);
travel(x,y+1);
}
}
}
public class runExtraCreditMaze {
public static void main (String [] args) { //JFrame panel and perimeters
JFrame output = new JFrame();
output.setSize(115, 150);
output.setTitle("The Rat Maze");
output.setLocationRelativeTo(null);
extraCreditMaze Maze = new extraCreditMaze();
output.setContentPane(Maze);
output.setVisible(true);
Thread runnable = new Thread(Maze); //Creates Runnable thread for Maze object
runnable.start(); //Starts Runnable thread of Maze object
}
}
Problem is, as you wrote with the "visited". You are missing an decision tree on what to do, when there is no valid move and you are not in the goal. You will need to allow your rat to back track itself. You will probably need to "free" the visited cells when returning from no valid move.
I will try to add some code samples when I get to IDE :)
update: this is very badly written, and it is a bit lagging. but it should work. It needs a bit of cleaning and verification... I reused your boolean variable, which is bad .. :) and switched the true/false. I will do a bit of cleaning up tomorrow just to leave a nicer answer, but I think you will manage to understand what is going on.
update2:I have cleaned it a bit. Important lessons here are as follows:
1) backtracking needs to be done when all 4 steps fails. When your rat have nowhere to go, you need to disqualify the cell from your shortest path (ratMaze[x][y]="open")
2) You need to change position of your rat, when you return from recursion call, but before you continue with next step into. You will also need to let your program know that you are returning from recursion (thus the isBacktracking)
private void repaintMaze(int x, int y) {
changedVisited(x, y); //changes traveled block to "visited"
repaint(); //repaints visited
isBacktracking = false;
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
private boolean travel(int x, int y) {
if (goal(x, y)) //checks if it's the goal/changes boolean
{
JOptionPane.showMessageDialog(this, "You did it, Dr. Cui!");//fun message!
return true;
}
if (boundaries(x, y) || visited(x, y)) //makes sure it's within bounds
return false;
repaintMaze(x, y);
boolean result; //recursive travel functions
result = travel(x - 1, y);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x + 1, y);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x, y - 1);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x, y + 1);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
ratMaze[x][y] = "open";
isBacktracking = true;
return false;
}
you should also add exit on close to your JFrame :) It will stop the application once you click the X button on the window itself
output.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
i'm trying to do a simple program with Dekker's Algorithm but with 3 processes. Here's my code:
class DekkerAlg {
static final int iter = 2000000;
static volatile int sharedResource = 0;
/* Thread P wants to enter in the CS */
static volatile boolean wantp = false;
/* Thread Q wants to enter in the CS */
static volatile boolean wantq = false;
/* Thread R wants to enter in the CS */
static volatile boolean wantr = false;
/* Who's next? */
static volatile int turn = 1;
class P extends Thread {
public void run() {
for (int i=0; i<iter; ++i) {
wantp = true;
while (wantq || wantr) {
if (turn == 2 || turn == 3) {
wantp = false;
while (turn == 2 || turn == 3)
Thread.yield();
wantp = true;
}
}
++sharedResource;
turn = 2;
wantp = false;
}
}
}
class Q extends Thread {
public void run() {
for (int i=0; i<iter; ++i) {
wantq = true;
while (wantp || wantr) {
if (turn == 1 || turn == 3) {
wantq = false;
while (turn == 1 || turn == 3)
Thread.yield();
wantq = true;
}
}
--sharedResource;
turn = 3;
wantq = false;
}
}
}
class R extends Thread {
public void run() {
for (int i=0; i<iter; ++i) {
wantr = true;
while (wantp || wantq) {
if (turn == 1 || turn == 2) {
wantr = false;
while (turn == 1 || turn == 2)
Thread.yield();
wantr = true;
}
}
++sharedResource;
turn = 1;
wantr = false;
}
}
}
DekkerAlg() {
Thread p = new P();
Thread q = new Q();
Thread r = new R();
p.start();
q.start();
r.start();
try {
p.join();
q.join();
r.join();
System.out.println("Shared Resource value: " + sharedResource);
System.out.println("Should be 2000000.");
}
catch (InterruptedException e) {}
}
public static void main(String[] args) {
new DekkerAlg();
}
}
I don't know if my code is 100% correct. If P wants to enter in the CS, first, he has to check if Q or R wants to enter too, if it isn't his turn, he waits. Same procedure with Thread Q and R.
With 2000000 iterations: the program doesn't work
With 200 iterations: the program works sometimes
I guess Dekker's Algorithm doesn't work for 3 processes but i need to know if my code is correct and why my program fail.
Thanks.
When trying to get an idea if any given implementation of an algorithm works, reason about it ("proof" of correctness) or test it.
With your implementation, have Q assign P's id to turn, and don't (instantiate, start, and) join R.
When refactoring to use instances of just one runnable class: volatile type[] declares a volatile reference to an array of type - you need something else.
With more than two processes, your extension will starve the process that, without being done, sets turn to the id of a process that will never set turn to any other value (is done or terminated), and any other processes neither done or terminated.
The difficult part will be mutual exclusion for 3 processes […] without [changing Dekker's] entire algorithm - you may find yourself retracing the history of MutEx implementations.
Early one were created with a model of memory much different from the JVM Memory Model.
Dekker's Algorithm doesn't work.
Let this sink in, the classic algorithm for consistency does not work and has not worked since about 1980 when IBM started releasing multi-CPU mainframes.
The hardware memory model is too weak; what happens is one of the threads observes the memory writes in the wrong order because one CPU can write to a variable while another CPU can read from it.
Source: https://jakob.engbloms.se/archives/65
A curious case was on some exam they had the Dekker's algorithm, and then the Peterson algorithm (unnamed) and some discussion on whether or not to trust the faster algorithm. My answer was I don't trust either of these two but only the atomic assembly instructions. My guess is they were looking for some risk-averseness. Doesn't matter. They got "don't write synchornization primitives in high-level languages". Turns out I was more right than I thought. My line of reasoning is was the assembly instructions are easier to prove. Turns out they also take care of the memory model.
I have a matrix that implements John Conway's life simulator in which every cell represents either life or lack of it.
Every life cycle follows these rules:
Any live cell with fewer than two live neighbors dies, as if caused by under-population.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if by overcrowding.
Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
Every cell will have a thread that will perform the changes by the rules listed above.
I have implemented these classes:
import java.util.Random;
public class LifeMatrix {
Cell[][] mat;
public Action currentAction = Action.WAIT_FOR_COMMAND;
public Action changeAction;
public enum Action {
CHECK_NEIGHBORS_STATE,
CHANGE_LIFE_STATE,
WAIT_FOR_COMMAND
}
// creates a life matrix with all cells alive or dead or random between dead or alive
public LifeMatrix(int length, int width) {
mat = new Cell[length][width];
for (int i = 0; i < length; i++) { // populate the matrix with cells randomly alive or dead
for (int j = 0; j < width; j++) {
mat[i][j] = new Cell(this, i, j, (new Random()).nextBoolean());
mat[i][j].start();
}
}
}
public boolean isValidMatrixAddress(int x, int y) {
return x >= 0 && x < mat.length && y >= 0 && y < mat[x].length;
}
public int getAliveNeighborsOf(int x, int y) {
return mat[x][y].getAliveNeighbors();
}
public String toString() {
String res = "";
for (int i = 0; i < mat.length; i++) { // populate the matrix with cells randomly alive or
// dead
for (int j = 0; j < mat[i].length; j++) {
res += (mat[i][j].getAlive() ? "+" : "-") + " ";
}
res += "\n";
}
return res;
}
public void changeAction(Action a) {
// TODO Auto-generated method stub
currentAction=a;
notifyAll(); //NOTIFY WHO??
}
}
/**
* Class Cell represents one cell in a life matrix
*/
public class Cell extends Thread {
private LifeMatrix ownerLifeMat; // the matrix owner of the cell
private boolean alive;
private int xCoordinate, yCoordinate;
public void run() {
boolean newAlive;
while (true) {
while (! (ownerLifeMat.currentAction==Action.CHECK_NEIGHBORS_STATE)){
synchronized (this) {//TODO to check if correct
try {
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted while waiting to check neighbors");
}}
}
// now check neighbors
newAlive = decideNewLifeState();
// wait for all threads to finish checking their neighbors
while (! (ownerLifeMat.currentAction == Action.CHANGE_LIFE_STATE)) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted while waiting to change life state");
};
}
// all threads finished checking neighbors now change life state
alive = newAlive;
}
}
// checking the state of neighbors and
// returns true if next life state will be alive
// returns false if next life state will be dead
private boolean decideNewLifeState() {
if (alive == false && getAliveNeighbors() == 3)
return true; // birth
else if (alive
&& (getAliveNeighbors() == 0 || getAliveNeighbors() == 1)
|| getAliveNeighbors() >= 4)
return false; // death
else
return alive; // same state remains
}
public Cell(LifeMatrix matLifeOwner, int xCoordinate, int yCoordinate, boolean alive) {
this.ownerLifeMat = matLifeOwner;
this.xCoordinate = xCoordinate;
this.yCoordinate = yCoordinate;
this.alive = alive;
}
// copy constructor
public Cell(Cell c, LifeMatrix matOwner) {
this.ownerLifeMat = matOwner;
this.xCoordinate = c.xCoordinate;
this.yCoordinate = c.yCoordinate;
this.alive = c.alive;
}
public boolean getAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
public int getAliveNeighbors() { // returns number of alive neighbors the cell has
int res = 0;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate - 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate + 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate][yCoordinate - 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate][yCoordinate + 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate - 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate + 1].alive)
res++;
return res;
}
}
public class LifeGameLaunch {
public static void main(String[] args) {
LifeMatrix lifeMat;
int width, length, populate, usersResponse;
boolean userWantsNewGame = true;
while (userWantsNewGame) {
userWantsNewGame = false; // in order to finish the program if user presses
// "No" and not "Cancel"
width = Integer.parseInt(JOptionPane.showInputDialog(
"Welcome to John Conway's life simulator! \n"
+ "Please enter WIDTH of the matrix:"));
length = Integer.parseInt(JOptionPane.showInputDialog(
"Welcome to John Conway's life simulator! \n"
+ "Please enter LENGTH of the matrix:"));
lifeMat = new LifeMatrix(length, width);
usersResponse = JOptionPane.showConfirmDialog(null, lifeMat + "\nNext cycle?");
while (usersResponse == JOptionPane.YES_OPTION) {
if (usersResponse == JOptionPane.YES_OPTION) {
lifeMat.changeAction(Action.CHECK_NEIGHBORS_STATE);
}
else if (usersResponse == JOptionPane.NO_OPTION) {
return;
}
// TODO leave only yes and cancel options
usersResponse = JOptionPane.showConfirmDialog(null, lifeMat + "\nNext cycle?");
}
if (usersResponse == JOptionPane.CANCEL_OPTION) {
userWantsNewGame = true;
}
}
}
}
My trouble is to synchronize the threads:
Every cell(a thread) must change its life/death state only after all threads have checked their neighbors. The user will invoke every next life cycle by clicking a button.
My logic, as can be understood from the run() method is to let every cell(thread) run and wait for the right action state that is represented by the variable currentAction in LifeMatrix class and go ahead and execute the needed action.
What I struggle with is how do I pass these messages to the threads to know when to wait and when execute next action?
Any suggestions to change the design of the program are very welcome as long as every cell will be implemented with a separate thread!
Using a CyclicBarrier should be easy to understand:
(updated to use 2 Barriers, and make use of inner class to make cell looks shorter and cleaner)
psuedo code:
public class LifeMatrix {
private CyclicBarrier cycleBarrier;
private CyclicBarrier cellUpdateBarrier;
//.....
public LifeMatrix(int length, int width) {
cycleBarrier = new CyclicBarrier(length * width + 1);
cellUpdateBarrier = new CyclicBarrier(length * width);
// follow logic of old constructor
}
public void changeAction(Action a) {
//....
cycleBarrier.await()
}
// inner class for cell
public class Cell implements Runnable {
// ....
#Override
public void run() {
while (...) {
cycleBarrier.await(); // wait until start of cycle
boolean isAlive = decideNewLifeState();
cellUpdateBarrier.await(); // wait until everyone completed
this.alive = isAlive;
}
}
}
}
I would solve this using two Phasers.
You use one Phaser to control cycles and one one to synchronize the cells when they determine if they are alive or not.
public class Cell extends Thread {
private LifeMatrix ownerLifeMat; // the matrix owner of the cell
private boolean alive;
private int xCoordinate, yCoordinate;
// Phaser that controls the cycles
private Phaser cyclePhaser;
// Phaser for cell synchronisation
private Phaser cellPhaser;
public Cell(LifeMatrix matLifeOwner, Phaser cyclePhaser, Phaser cellPhaser,
int xCoordinate, int yCoordinate, boolean alive) {
this.ownerLifeMat = matLifeOwner;
this.cyclePhaser = cyclePhaser;
this.cellPhaser = cellPhaser;
this.xCoordinate = xCoordinate;
this.yCoordinate = yCoordinate;
this.alive = alive;
// Register with the phasers
this.cyclePhaser.register();
this.cellPhaser.register();
}
public void run() {
boolean newAlive;
while (true) {
// Await the next cycle
cyclePhaser.arriveAndAwaitAdvance();
// now check neighbors
newAlive = decideNewLifeState();
// Wait until all cells have checked their state
cellPhaser.arriveAndAwaitAdvance();
// all threads finished checking neighbors now change life state
alive = newAlive;
}
}
// Other methods redacted
}
You control the cycles by having the main thread register on the cyclePhaser
and have it arrive on it to start the next cycle.
I want to make a plane (Thread) fly from one airfield to another. When a plane is starting the airfield is blocked for 5 sec. (if another plane wants to land or take off - must wait). If a plane reach its destination it lands (if airfield is not blocked by another plane) and then takes a random airfield and fly there and so on....
I have questions in comments - how to make a thread wait ? And what else is wrong with my code ?
Here is my class Samolot aka Plane:
public class Samolot extends Thread{
int id;
double paliwo;
Lotnisko source; //Lotnisko aka airfield
Lotnisko dest;
double xPosition;
double yPosition;
double xTarget;
double yTarget;
public Samolot(Lotnisko source, Lotnisko dest) {
this.source = source;
this.dest = dest;
paliwo = 100;
}
public void run(){
while(true){
tryStart();
}
}
public void tryStart(){
if(source.pas == true){ // if true the airfield is not blocked and we can go
source.timer(); // its a method in class Lotnisko, makes pas = false for 8sec
lecimy(source, dest);
}
else if(source.pas == false){
// how to make a thread wait ?
}
}
public void tryLadowanie(){
if(dest.pas == true){
dest.timer();
source = dest;
dest = Rand(source);
tryStart();
}
else if(dest.pas == false){
//how to make a thread wait ?
}
}
public void lecimy(Lotnisko source, Lotnisko dest){
xPosition = source.coords.getX();
yPosition = source.coords.getY();
xTarget = dest.coords.getX();
yTarget = dest.coords.getY();
while( (xPosition != xTarget) && (yPosition != yTarget) ){
update();
try{
sleep(100);// ok
}
catch (InterruptedException e) {
System.out.println("Error");
}
}
tryLadowanie();
}
public void update() {
paliwo -= 0.05;
double dx = xTarget - xPosition;
double dy = yTarget - yPosition;
double length = sqrt(dx*dx+dy*dy);
dx /= length;
dy /= length;
if (Math.abs(dest.coords.getX() - source.coords.getX()) < 1)
dx = 0;
if (Math.abs(dest.coords.getY() - source.coords.getY()) < 1)
dy = 0;
xPosition += dx;
yPosition += dy;
}
public Point getPositions() {
Point curPos = new Point((int)xPosition, (int)yPosition);
return curPos;
}
OK, so your plane is a thread and your airfields are the shared resource. So to make your plane (thread) wait, you'll need to synchronized on the shared resource (airfield). You'll probably do something like this.
For take off,
public void tryStart() {
synchronized(source) { // try to obtain source lock
try {
Thread.sleep(5000); // lock it for 5 seconds.
}
catch(Exception ignore) {
// You'll need to decide what to do if something interrupts the thread while it's "sleeping" (ie. locked) on the source airfield. Normally, this should not happen.
}
}
// After 5 seconds, releases lock on airfield "source" and Plane starts flying
}
For landing,
public void tryLadowanie() {
synchronized(dest) { // try to obtain dest lock
// successfully obtained lock.
// perform your landing
}
// plane landed and releases "dest" resource for other planes (ie. threads)
}
For a more complete picture of plane flying.
public void run(){
while(true){
tryStart(); // take off from source
lecimy(); // fly the plane. Method will only return when plane reaches destination.
tryLadowanie(); // land the plane
source = dest;
dest = Rand(source); // returns a new destination but can't be the same as source
}
}
public void tryStart(){
synchronized(source) {
try {
Thread.sleep(5000);
}
catch(Exception ignore) { }
}
}
public void tryLadowanie(){
synchronized(dest) {
// land the plane
}
}
Not a complete answer but wait method is used to wait the thread and notify is used to wake up the thread that is in wait.
Check this for more info on wait and notify method:
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notify()
Use general java object exp.
Object lock=new Object();
To wait :
Synchronized(lock)
{
lock.wait();
}
To release or free the lock from another thread
On same lock object
Synchronized(lock)
{
lock.notify();
}
I'm creating a program in Java that solves the n-puzzle, without using heuristics, simply just with depth-first and breadth-first searches of the state space. I'm struggling a little bit with my implementation of depth-first search. Sometimes it will solve the given puzzle, but other times it seems to give up early.
Here's my DFS class. DepthFirstSearch() is passed a PuzzleBoard, which is initially generated by shuffling a solved board (to ensure that the board is in a solvable state).
public class DepthFirst {
static HashSet<PuzzleBoard> usedStates = new HashSet<PuzzleBoard>();
public static void DepthFirstSearch(PuzzleBoard currentBoard)
{
// If the current state is the goal, stop.
if (PuzzleSolver.isGoal(currentBoard)) {
System.out.println("Solved!");
System.exit(0);
}
// If we haven't encountered the state before,
// attempt to find a solution from that point.
if (!usedStates.contains(currentBoard)) {
usedStates.add(currentBoard);
PuzzleSolver.print(currentBoard);
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != 0) {
System.out.println("Moving left");
DepthFirstSearch(PuzzleSolver.moveLeft(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != PuzzleSolver.n-1) {
System.out.println("Moving down");
DepthFirstSearch(PuzzleSolver.moveDown(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != PuzzleSolver.n-1) {
System.out.println("Moving right");
DepthFirstSearch(PuzzleSolver.moveRight(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != 0) {
System.out.println("Moving up");
DepthFirstSearch(PuzzleSolver.moveUp(currentBoard));
}
return;
} else {
// Move up a level in the recursive calls
return;
}
}
}
I can assert that my moveUp(), moveLeft(), moveRight(), and moveDown() methods and logic work correctly, so the problem must lie somewhere else.
Here's my PuzzleBoard object class with the hashCode and equals methods:
static class PuzzleBoard {
short[][] state;
/**
* Default constructor for a board of size n
* #param n Size of the board
*/
public PuzzleBoard(short n) {
state = PuzzleSolver.getGoalState(n);
}
public PuzzleBoard(short n, short[][] initialState) {
state = initialState;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(state);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PuzzleBoard other = (PuzzleBoard) obj;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (state[i][j] != other.state[i][j])
return false;
}
}
return true;
}
}
As previously stated, sometimes the search works properly and finds a path to the solution, but other times it stops before it finds a solution and before it runs out of memory.
Here is a snippet of the output, beginning a few moves before the search stops searching.
...
Moving down
6 1 3
5 8 2
0 7 4
Moving right
6 1 3
5 8 2
7 0 4
Moving left
Moving right
Moving up
6 1 3
5 0 2
7 8 4
Moving left
Moving down
Moving right
Moving up
Moving up
Moving right
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
...
I truncated it early for brevity, but it ends up just moving up and down dozens of times and never hits the solved state.
Can anyone shed light on what I'm doing wrong?
Edit: Here is MoveUp(). The rest of the move methods are implemented in the same way.
/**
* Move the blank space up
* #return The new state of the board after the move
*/
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
I have had many problems with hashset in the past best thing to try is not to store object in hashset but try to encode your object into string.
Here is a way to do it:-
StringBuffer encode(PuzzleBoard b) {
StringBuffer buff = new StringBuffer();
for(int i=0;i<b.n;i++) {
for(int j=0;j<b.n;j++) {
// "," is used as separator
buff.append(","+b.state[i][j]);
}
}
return buff;
}
Make two changes in the code:-
if(!usedStates.contains(encode(currentBoard))) {
usedStates.add(encode(currentBoard));
......
}
Note:- Here no need to write your own hashcode function & also no need to implement equals function as java has done it for you in StringBuffer.
I got one of the problems in your implementation:-
In th following code:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Here you are using the reference of same array as newState from currentState.state so when you make changes to newState your currentState.state will also change which will affect DFS when the call returns. To prevent that you should initialize a new array. Heres what to be done:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = new short[n][n];
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
newState[i][j] = currentState.state[i][j];
}
}
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Do this change for all moveup,movedown....
Moreover I donot think your hashset is working properly because if it was then you would always find your new state in hashset and your program would stop. As in equals you comparing the state arrays with same reference hence will always get true. Please try and use my encode function as hash.