This commit is contained in:
violette 2024-03-24 13:14:37 -04:00
parent 97ce72dd93
commit 3b99a35740
9 changed files with 289 additions and 139 deletions

View file

@ -5,51 +5,68 @@ import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
/**
* Hello world!
*
*/
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class App {
static private int numStops = 10;
static private int numBusses = 5;
static private int numStopPerBus = 2;
static private int numPassengersPerBus = 2;
static private int numPassengersPerStop = 5;
static private int numStopPerBus = 8;
static private int numStops = numBusses * numStopPerBus;
static private int numPassengersPerBus = 10;
static private int numPassengersPerStop = 3;
static private int numPassengers = numPassengersPerStop * numStops;
static private int numThreads = 5;
static private int timeBetweenStops = 0;
static private int timeEmbark = 0;
static private int numThreadsBus = 5;
static private int numThreadsStop = 2;
static private int timeBetweenStops = 5;
static private int timeEmbark = 2;
public static void main(String[] args) {
ExecutorService threads = Executors.newFixedThreadPool(numThreads);
ExecutorService threadsBus = Executors.newFixedThreadPool(numThreadsBus);
ExecutorService threadsStop = Executors.newFixedThreadPool(numThreadsStop);
ArrayList<Stop> stops = new ArrayList<Stop>();
ArrayList<Bus> busses = new ArrayList<Bus>();
ArrayList<Passenger> passengers = new ArrayList<Passenger>();
BlockingQueue<BusInformationMessage> blockingQueue = new LinkedBlockingQueue<BusInformationMessage>();
// make stops
for (int k = 0; k < numStops; k++) {
Stop s = new Stop(k, numPassengersPerStop);
stops.add(s);
s.setBlockingQueue(blockingQueue);
//threads.submit(s);
stops.add(s);
s.setThreadPool(threadsStop);
threadsStop.submit(s);
//s.run();
}
// make busses
for (int k = 0; k < numBusses; k++) {
if (numStopPerBus > numStops)
{System.out.println("More stops per bus than stops."); return;}
ArrayList<Stop> s_list = new ArrayList<Stop>();
Stop s;
// add stop. Make a bus doesnt stop multiple time at the same stop
while (s_list.size() < numStopPerBus) {
do {
s = stops.get((int) (Math.random() * numStops));
} while (s_list.contains(s));
s_list.add(s);
}
Bus b = new Bus(s_list, k, timeBetweenStops, timeEmbark, numPassengersPerBus);
b.setBlockingQueue(blockingQueue);
busses.add(b);
}
// make passenger
int idPassenger = 0;
for (Bus b : busses) {
for (Stop start : b.getStops()) {
// make sure passenger can leave.
if (start == b.getTerminus())
continue;
@ -70,22 +87,30 @@ public class App {
}
}
// pretty print!
for (Bus b : busses) {
b.printDetails();
}
System.out.println("-----".repeat(5) + " START " + "-----".repeat(5));
// start bus thread
// (here so init logs are clean)
for (Bus b : busses) {
threads.submit(b);
//b.run();
threadsBus.submit(b);
}
threads.shutdown();
// block bus pool
threadsBus.shutdown();
try {
threads.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
threadsBus.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (InterruptedException e) {}
// block stop pool once bus have finished
threadsStop.shutdown();
try {
threadsStop.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (InterruptedException e) {}
}
}

View file

@ -1,6 +1,7 @@
package usherbrooke.ift630;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
public class Bus extends Thread {
private ArrayList<Passenger> passengers;
@ -10,22 +11,29 @@ public class Bus extends Thread {
private int maxCapacity;
private int currentCapacity;
private int timeBetweenStops;
private int timeToNextStop;
private int timeEmbark;
private Stop nextStop;
private BlockingQueue<BusInformationMessage> blockingQueue;
// returns time for a single passenger to embark.
private int timeEmbark() {
return (int) (Math.random() * timeEmbark);
}
private int timeBetweenStops() {
return (int) (Math.random() * timeBetweenStops);
// set time between stop.
private int calculateTimeBetweenStops() {
timeToNextStop = (int) ((timeBetweenStops / 3) + (Math.random() * 2 * timeBetweenStops / 3));
return timeToNextStop;
}
// check if a passenger must leave at next stop.
private boolean stopAsked() {
boolean res = false;
for (Passenger p : passengers){
if (p.getDest() == nextStop) {
res = true;
Logger.getInstance().print(id, "[BUS] " + name + " stop asked!");
break;
}
}
@ -33,25 +41,39 @@ public class Bus extends Thread {
return res;
}
private Stop goToNextStop() {
// travel to next stop. Waits the travel time.
private Stop goToNextStop() throws InterruptedException, IndexOutOfBoundsException {
// if no reason to stop, skip current stop
try {
boolean nextStopEmpty, overMaxCapacity;
do {
nextStop = stops.remove(0);
} while ((getNextStopPassengers().isEmpty() || currentCapacity >= maxCapacity) && !stopAsked());
} catch (IndexOutOfBoundsException e) {
nextStop = null;
}
sendNextStopInfo();
waitStop();
overMaxCapacity = currentCapacity >= maxCapacity;
nextStopEmpty = getNextStopPassengers().isEmpty();
if (overMaxCapacity)
Logger.getInstance().print(id, "[BUS] " + name + " im full, sorry!");
if (nextStopEmpty && !stopAsked())
Logger.getInstance().print(id, "[BUS] " + name + " next " + nextStop.getStopName() + " is empty!");
} while (!stopAsked() && (nextStopEmpty || overMaxCapacity));
try {
Thread.sleep(timeBetweenStops() * 1000);
} catch (InterruptedException e) {
}
return nextStop;
}
// TODO what
// send Bus info msg to next stop
private void sendNextStopInfo() throws InterruptedException{
BusInformationMessage info = new BusInformationMessage(this, nextStop, timeToNextStop);
synchronized(blockingQueue) {
blockingQueue.put(info);
}
}
// get all passenger waiting at next stop
// useful for knowing if we should stop
private ArrayList<Passenger> getNextStopPassengers() {
ArrayList<Passenger> res = new ArrayList<Passenger>();
@ -66,57 +88,82 @@ public class Bus extends Thread {
return res;
}
// lock until passenger got in
private void waitEmbark() throws InterruptedException {
synchronized (this) {
sleep(timeEmbark());
}
}
// lock until passenger got out
private void waitStop() throws InterruptedException {
synchronized (this) {
sleep(timeToNextStop);
}
}
@Override
public void run() {
try {
// run until terminus
while (nextStop != null) {
Logger.getInstance().print(id, "[BUS] hop into " + name + " at stop " + nextStop.getName() + "!");
// new stop !
Logger.getInstance().print(id, "[BUS] " + name + " reached stop " + nextStop.getStopName() + "!");
disembarkPassengers();
embarkPassengers();
calculateTimeBetweenStops();
try {
nextStop = goToNextStop();
} catch (IndexOutOfBoundsException e) {
nextStop = null;
}
} catch (Exception e) {
Logger.getInstance().print(id, "[BUS] exception: " + e.getMessage());
}
Logger.getInstance().print(id, "[BUS]" + name + " exiting!");
} catch (InterruptedException e) {
Logger.getInstance().print(id, "[BUS] exception: " + e.toString());
}
Logger.getInstance().print(id, "[BUS] " + name + " exiting!");
}
Bus(ArrayList<Stop> s, int id, int timeStop, int timeEmbark, int maxCapacity) {
this.timeBetweenStops = timeStop;
this.timeEmbark = timeEmbark;
this.timeBetweenStops = timeStop * 1000 + 1;
this.timeEmbark = timeEmbark * 1000 + 1;
this.name = "Bus n°" + id;
this.id = id;
this.passengers = new ArrayList<Passenger>();
this.stops = s;
this.nextStop = stops.remove(0);
this.nextStop = stops.get(0);
this.currentCapacity = 0;
this.maxCapacity = maxCapacity;
}
public synchronized void disembarkPassengers() {
Logger.getInstance().print(id, "[BUS] waiting mutex for " + nextStop.getName());
synchronized (nextStop.getMutex()) {
// disembark passenger at a stop. Synchronizes, locks on that stop, and waits.
public synchronized void disembarkPassengers() throws InterruptedException {
// lock on next stop
synchronized (nextStop) {
for (Passenger p : passengers) {
waitEmbark();
Logger.getInstance().print(id,
"\t[DISEMBARK] " + p.getName() + " at " + nextStop.getName());
"\t[DISEMBARK] " + p.getName() + " at " + nextStop.getStopName());
if (p.getDest() == nextStop) {
p.disembark();
currentCapacity--;
}
}
Logger.getInstance().print(id, "[BUS] release mutex for " + nextStop.getName());
}
}
public synchronized void embarkPassengers() {
Logger.getInstance().print(id, "[BUS] waiting mutex for " + nextStop.getName());
synchronized (nextStop.getMutex()) {
// embark passenger at a stop. Synchronizes, locks on that stop, and waits.
// check for overflow, and if passenger should embark in the first place
public synchronized void embarkPassengers() throws InterruptedException {
synchronized (nextStop) {
try {
ArrayList<Passenger> list = nextStop.getPassengerByDest(stops);
for (Passenger p : list) {
Thread.sleep(timeEmbark() * 1000);
waitEmbark();
if (currentCapacity >= maxCapacity)
continue;
passengers.add(p);
@ -124,40 +171,46 @@ public class Bus extends Thread {
currentCapacity++;
Logger.getInstance().print(id,
"\t[EMBARK] " + p.getName() + " at " + nextStop.getName());
"\t[EMBARK] " + p.getName() + " at " + nextStop.getStopName());
}
} catch (IndexOutOfBoundsException | InterruptedException e) {
} catch (IndexOutOfBoundsException e) {
Logger.getInstance().print(id, "Exception: " + e.getMessage());
}
Logger.getInstance().print(id, "[BUS] release mutex for " + nextStop.getName());
}
}
// pretty print!
public void printDetails(int indent) {
Logger.getInstance().print(id, "\t".repeat(indent) + "---".repeat(3) + " Bus details " + "---".repeat(3));
Logger.getInstance().print(id, "\t".repeat(indent) + name);
Logger.getInstance().print(id, "\t".repeat(indent) + "time between stops: " + timeBetweenStops);
Logger.getInstance().print(id, "\t".repeat(indent) + "max capacity: " + maxCapacity);
Logger.getInstance().print(id, "\t".repeat(indent) + "current stop: " + nextStop.getName());
Logger.getInstance().print(id, "\t".repeat(indent) + "current stop: " + nextStop.getStopName());
Logger.getInstance().print(id, "\t".repeat(indent) + "stops: ");
if (nextStop != stops.get(0))
nextStop.printDetails(id, indent + 1);
for (Stop s : stops) {
s.printDetails(id, indent + 1);
}
}
// pretty print w/ 0 indent
public void printDetails() {
printDetails(0);
}
// return stop list
public ArrayList<Stop> getStops() {
ArrayList<Stop> res = new ArrayList<Stop>(stops);
if (nextStop != stops.get(0))
res.add(0, nextStop);
return res;
}
// return last stop
public Stop getTerminus() {
return stops.get(stops.size() - 1);
}
@ -165,4 +218,8 @@ public class Bus extends Thread {
public String getNameBus() {
return name;
}
public void setBlockingQueue(BlockingQueue<BusInformationMessage> q) {
blockingQueue = q;
}
}

View file

@ -0,0 +1,39 @@
package usherbrooke.ift630;
class BusInformationMessage {
private Bus bus; // origin
private Stop stop; //dest
private int timeToStop; // info
public BusInformationMessage(Bus b, Stop s, int time) {
this.bus = b;
this.stop = s;
this.timeToStop = time;
}
// throws unauth if stop shouldt see
public Bus getBus(Stop s) throws UnauthorizedException {
if (s != stop) {
throw new UnauthorizedException("UnauthorizedException");
}
return bus;
}
// throws unauth if stop shouldt see
public Stop getStop(Stop s) throws UnauthorizedException {
if (s != stop) {
throw new UnauthorizedException("UnauthorizedException");
}
return stop;
}
// throws unauth if stop shouldt see
public int getTimeToStop(Stop s) throws UnauthorizedException {
if (s != stop) {
throw new UnauthorizedException("UnauthorizedException");
}
return timeToStop;
}
}

View file

@ -0,0 +1,9 @@
package usherbrooke.ift630;
public class ExitException extends Exception {
ExitException() {}
public ExitException(String message) {
super(message);
}
}

View file

@ -1,10 +0,0 @@
package usherbrooke.ift630;
public class NotFoundException extends Exception {
NotFoundException() {}
public NotFoundException(String message)
{
super(message);
}
}

View file

@ -1,10 +0,0 @@
package usherbrooke.ift630;
public class OverCapacityException extends Exception {
OverCapacityException() {}
public OverCapacityException(String message)
{
super(message);
}
}

View file

@ -14,8 +14,10 @@ public class Passenger {
this.start = start;
}
// unused, *yet*
public synchronized void embark() {}
// unused, *yet*
public synchronized void disembark() {}
public Stop getStart() {
@ -30,16 +32,19 @@ public class Passenger {
return name;
}
// Pretty print, with color!
public void printDetails(int color, int indent) {
Logger.getInstance().print(color, "\t".repeat(indent) + "---".repeat(3) + " Passenger details " + "---".repeat(3));
Logger.getInstance().print(color, "\t".repeat(indent) + name + " start: " + start.getName() + " dest: " + dest.getName());
Logger.getInstance().print(color, "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName());
}
// Pretty print, with indent!
public void printDetails(int indent) {
Logger.getInstance().print(id, "\t".repeat(indent) + "---".repeat(3) + " Passenger details " + "---".repeat(3));
Logger.getInstance().print(id, "\t".repeat(indent) + name + " start: " + start.getName() + " dest: " + dest.getName());
Logger.getInstance().print(id, "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName());
}
// Pretty print!
public void printDetails() {
printDetails(0);
}

View file

@ -1,28 +1,61 @@
package usherbrooke.ift630;
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
public class Stop implements Runnable {
public class Stop extends Thread {
private String name;
private int id;
private int maxCapacity;
private int indent = 0;
private ArrayList<Passenger> passengers;
private Lock mutex = new ReentrantLock();
private ExecutorService threads;
private BlockingQueue<BusInformationMessage> blockingQueue;
// TODO lock mutex when stop is used
@Override
public void run() {
// xd do nothing for now
//for (Passenger p : passengers) {
// //
//}
// print bus info times.
private void displayInfos(int indent) throws InterruptedException, ExitException{
BusInformationMessage info = null;
// lock queue, get head
synchronized (blockingQueue) {
info = blockingQueue.poll();
}
// get infos
try {
try {
int time = info.getTimeToStop(this) / 1000;
// if everything is alright, print
Logger.getInstance().print(id,
"\t".repeat(indent) + "[STOP] " + info.getBus(this).getNameBus() + " arrives in " + time + "s");
// else, catch
} catch (NullPointerException e) {}
} catch (UnauthorizedException e) {
// if unauth, requeue message.
synchronized (blockingQueue) {
blockingQueue.add(info);
}
}
// loop, and ensure that every stop is reactive
synchronized (this) {
threads.submit(this);
sleep(10);
throw new ExitException();
}
}
@Override
public void run() {
try {
for (;;) {
displayInfos(indent);
}
} catch (InterruptedException | ExitException e) {}
}
// run once. Then, queue the same thread, and exit.
// Message a bus their current number of passenger ; and the
// number of passenger willing to take this bus.
Stop(int id, int maxCapacity) {
this.id = id;
this.name = "Stop " + id;
@ -30,20 +63,18 @@ public class Stop implements Runnable {
this.maxCapacity = maxCapacity;
}
public Passenger getPassenger() {
return passengers.get(0);
}
public void addPassenger(Passenger p) {
passengers.add(p);
}
// return all passenger that stops at a stop in the list
public ArrayList<Passenger> getPassengerByDest(ArrayList<Stop> list) {
// res for a little cleaner code
ArrayList<Passenger> res = new ArrayList<Passenger>();
// for all given stop
for (Stop s : list) {
// for all passenger at this stop
for (Passenger p : passengers) {
// if they stop at this stop, add to res
if (p.getDest() == s) {
res.add(p);
}
@ -53,7 +84,7 @@ public class Stop implements Runnable {
return res;
}
public String getName() {
public String getStopName() {
return name;
}
@ -65,10 +96,6 @@ public class Stop implements Runnable {
return maxCapacity;
}
public Lock getMutex() {
return mutex;
}
public void printDetails(int color, int indent) {
Logger.getInstance().print(color, "\t".repeat(indent) + "---".repeat(3) + " Stop details " + "---".repeat(3));
Logger.getInstance().print(color, "\t".repeat(indent) + name);
@ -91,24 +118,23 @@ public class Stop implements Runnable {
printDetails(0);
}
public void busArrive() {
synchronized(this) {
mutex.lock();
}
}
public void busLeave() {
synchronized(this) {
mutex.unlock();
}
}
public void removePassenger(Passenger p) {
// Logger.getInstance().print(id, "Passenger " + p.getName() + " left " + name);
try {
passengers.remove(p);
} catch(Exception e) {
} catch (Exception e) {
System.out.println("exception" + e.getMessage());
}
}
public void setIndent(int indent) {
this.indent = indent;
}
public void setBlockingQueue(BlockingQueue<BusInformationMessage> q) {
blockingQueue = q;
}
public void setThreadPool(ExecutorService threads) {
this.threads = threads;
}
}

View file

@ -0,0 +1,9 @@
package usherbrooke.ift630;
public class UnauthorizedException extends Exception {
public UnauthorizedException() {}
public UnauthorizedException(String message) {
super(message);
}
}