From 9a0c17edb7754399c8154f2e2d314ec7e174efa6 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Tue, 15 Oct 2019 21:57:11 +0200 Subject: [PATCH] HW1: mandatory part done --- hw1/Ex1/.idea/workspace.xml | 158 +++--- hw1/Ex2/.idea/Ex2.iml | 11 + hw1/Ex2/.idea/misc.xml | 9 + hw1/Ex2/.idea/modules.xml | 8 + hw1/Ex2/.idea/uiDesigner.xml | 124 +++++ hw1/Ex2/.idea/vcs.xml | 6 + hw1/Ex2/.idea/workspace.xml | 476 +++++++++++++++++++ hw1/Ex2/src/explicit/ExplicitValetQueue.java | 64 +++ hw1/Ex2/src/explicit/Main.java | 28 ++ hw1/Ex2/src/implicit/ImplicitValetQueue.java | 42 ++ hw1/Ex2/src/implicit/Main.java | 28 ++ hw1/Ex2/src/semaphore/Car.java | 5 + hw1/Ex2/src/semaphore/Main.java | 1 + hw1/Ex2/src/semaphore/ValetQueue.java | 29 +- hw1/submission.tex | 18 +- 15 files changed, 920 insertions(+), 87 deletions(-) create mode 100644 hw1/Ex2/.idea/Ex2.iml create mode 100644 hw1/Ex2/.idea/misc.xml create mode 100644 hw1/Ex2/.idea/modules.xml create mode 100644 hw1/Ex2/.idea/uiDesigner.xml create mode 100644 hw1/Ex2/.idea/vcs.xml create mode 100644 hw1/Ex2/.idea/workspace.xml create mode 100644 hw1/Ex2/src/explicit/ExplicitValetQueue.java create mode 100644 hw1/Ex2/src/explicit/Main.java create mode 100644 hw1/Ex2/src/implicit/ImplicitValetQueue.java create mode 100644 hw1/Ex2/src/implicit/Main.java diff --git a/hw1/Ex1/.idea/workspace.xml b/hw1/Ex1/.idea/workspace.xml index dd7563b..3b92859 100644 --- a/hw1/Ex1/.idea/workspace.xml +++ b/hw1/Ex1/.idea/workspace.xml @@ -2,11 +2,17 @@ - - - - - + + + + + + + + + + + - + @@ -32,9 +38,10 @@ - + + @@ -44,17 +51,17 @@ - + - + - + @@ -66,8 +73,8 @@ - - + + @@ -75,8 +82,8 @@ - - + + @@ -99,15 +106,11 @@ - + - - - - - - + + @@ -140,8 +143,6 @@ - - @@ -212,6 +213,8 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1571167105834 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No facets are configured + + + + + + + + + + + + + + + + + + + + + + Ex2 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw1/Ex2/src/explicit/ExplicitValetQueue.java b/hw1/Ex2/src/explicit/ExplicitValetQueue.java new file mode 100644 index 0000000..598be1f --- /dev/null +++ b/hw1/Ex2/src/explicit/ExplicitValetQueue.java @@ -0,0 +1,64 @@ +package explicit; + +import semaphore.Car; +import semaphore.Queue; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +public class ExplicitValetQueue implements Queue { + private final List waitingCars; + private final int queueMaxSize; + private final ReentrantLock lock; + private final Condition full, empty; + + + public ExplicitValetQueue(int queueMaxSize) { + this.queueMaxSize = queueMaxSize; + waitingCars = new ArrayList<>(this.queueMaxSize); + lock = new ReentrantLock(); + full = lock.newCondition(); + empty = lock.newCondition(); + } + + @Override + public void put(Car element) throws InterruptedException { + lock.lock(); + try { + while (waitingCars.size() >= this.queueMaxSize) { + full.await(); + } + + waitingCars.add(element); + System.out.println("Car with plate " + element.getPlate() + " in queue"); + System.out.println("Now waiting: " + waitingCars); + + empty.signal(); + } finally { + lock.unlock(); + } + } + + @Override + public Car take() throws InterruptedException { + final Car c; + lock.lock(); + try { + while (waitingCars.isEmpty()) { + empty.await(); + } + + c = waitingCars.remove(waitingCars.size() - 1); + System.out.println("Car with plate " + c.getPlate() + " will be parked now"); + System.out.println("Now waiting: " + waitingCars); + + full.signal(); + } finally { + lock.unlock(); + } + return c; + } +} diff --git a/hw1/Ex2/src/explicit/Main.java b/hw1/Ex2/src/explicit/Main.java new file mode 100644 index 0000000..eb364a2 --- /dev/null +++ b/hw1/Ex2/src/explicit/Main.java @@ -0,0 +1,28 @@ +package explicit; + +import semaphore.Car; +import semaphore.CarSimulation; +import semaphore.Queue; +import semaphore.ValetSimulation; + +public class Main { + // Maximum number of cars on the queue for a valet parking service + private static final int QUEUE_SIZE = 10; + // Simulated number of cars + public static final int NUM_CARS = 150; + // Simulated number of valets + private static final int NUM_VALETS = 5; + + public static void main(String[] args) { + // The shared queue + final Queue valetQueue = new ExplicitValetQueue(QUEUE_SIZE); + // Starting the threads simulating the cars + for (int i = 0; i < NUM_CARS; i++) { + new Thread(new CarSimulation(valetQueue, new Car(i))).start(); + } + // Starting the threads simulating the valets + for (int i = 0; i < NUM_VALETS; i++) { + new Thread(new ValetSimulation(valetQueue), "Valet " + i ).start(); + } + } +} diff --git a/hw1/Ex2/src/implicit/ImplicitValetQueue.java b/hw1/Ex2/src/implicit/ImplicitValetQueue.java new file mode 100644 index 0000000..e9534e0 --- /dev/null +++ b/hw1/Ex2/src/implicit/ImplicitValetQueue.java @@ -0,0 +1,42 @@ +package implicit; + +import semaphore.Car; +import semaphore.Queue; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; + +public class ImplicitValetQueue implements Queue { + private final List waitingCars; + private final int queueMaxSize; + + public ImplicitValetQueue(int queueMaxSize) { + this.queueMaxSize = queueMaxSize; + waitingCars = new ArrayList<>(this.queueMaxSize); + } + + @Override + public synchronized void put(Car element) throws InterruptedException { + while (waitingCars.size() >= queueMaxSize) { + wait(); + } + + waitingCars.add(element); + System.out.println("Car with plate " + element.getPlate() + " in queue"); + System.out.println("Now waiting: " + waitingCars); + notifyAll(); + } + + @Override + public synchronized Car take() throws InterruptedException { + while (waitingCars.isEmpty()) { + wait(); + } + Car c = waitingCars.remove(waitingCars.size() - 1); + System.out.println("Car with plate " + c.getPlate() + " will be parked now"); + System.out.println("Now waiting: " + waitingCars); + notifyAll(); + return c; + } +} diff --git a/hw1/Ex2/src/implicit/Main.java b/hw1/Ex2/src/implicit/Main.java new file mode 100644 index 0000000..af5b19c --- /dev/null +++ b/hw1/Ex2/src/implicit/Main.java @@ -0,0 +1,28 @@ +package implicit; + +import semaphore.Car; +import semaphore.CarSimulation; +import semaphore.Queue; +import semaphore.ValetSimulation; + +public class Main { + // Maximum number of cars on the queue for a valet parking service + private static final int QUEUE_SIZE = 10; + // Simulated number of cars + public static final int NUM_CARS = 150; + // Simulated number of valets + private static final int NUM_VALETS = 5; + + public static void main(String[] args) { + // The shared queue + final Queue valetQueue = new ImplicitValetQueue(QUEUE_SIZE); + // Starting the threads simulating the cars + for (int i = 0; i < NUM_CARS; i++) { + new Thread(new CarSimulation(valetQueue, new Car(i))).start(); + } + // Starting the threads simulating the valets + for (int i = 0; i < NUM_VALETS; i++) { + new Thread(new ValetSimulation(valetQueue), "Valet " + i ).start(); + } + } +} diff --git a/hw1/Ex2/src/semaphore/Car.java b/hw1/Ex2/src/semaphore/Car.java index e84f363..28781f2 100644 --- a/hw1/Ex2/src/semaphore/Car.java +++ b/hw1/Ex2/src/semaphore/Car.java @@ -22,4 +22,9 @@ public class Car { int time = generator.nextInt(MAX_PARKING_TIME); Thread.sleep(time); } + + @Override + public String toString() { + return "" + plate; + } } diff --git a/hw1/Ex2/src/semaphore/Main.java b/hw1/Ex2/src/semaphore/Main.java index 9246186..bad7627 100644 --- a/hw1/Ex2/src/semaphore/Main.java +++ b/hw1/Ex2/src/semaphore/Main.java @@ -1,5 +1,6 @@ package semaphore; + public class Main { // Maximum number of cars on the queue for a valet parking service private static final int QUEUE_SIZE = 10; diff --git a/hw1/Ex2/src/semaphore/ValetQueue.java b/hw1/Ex2/src/semaphore/ValetQueue.java index 51b4902..5cf9b23 100644 --- a/hw1/Ex2/src/semaphore/ValetQueue.java +++ b/hw1/Ex2/src/semaphore/ValetQueue.java @@ -11,14 +11,33 @@ public class ValetQueue implements Queue { public ValetQueue(int queueMaxSize) { this.queueMaxSize = queueMaxSize; - waitingCars = new ArrayList<>(queueMaxSize); - empty = new Semaphore (queueMaxSize); + waitingCars = new ArrayList<>(this.queueMaxSize); + empty = new Semaphore (this.queueMaxSize); full = new Semaphore(0); mutex = new Semaphore(1); } - // TODO: Implement method put - - // TODO: Implement method take + @Override + public void put(Car element) throws InterruptedException { + empty.acquire(); + mutex.acquire(); + waitingCars.add(element); + System.out.println("Car with plate " + element.getPlate() + " in queue"); + System.out.println("Now waiting: " + waitingCars); + mutex.release(); + full.release(); + } + @Override + public Car take() throws InterruptedException { + final Car c; + full.acquire(); + mutex.acquire(); + c = waitingCars.remove(waitingCars.size() - 1); + System.out.println("Car with plate " + c.getPlate() + " will be parked now"); + System.out.println("Now waiting: " + waitingCars); + mutex.release(); + empty.release(); + return c; + } } diff --git a/hw1/submission.tex b/hw1/submission.tex index 6646a00..bcda1f3 100644 --- a/hw1/submission.tex +++ b/hw1/submission.tex @@ -1,17 +1,18 @@ \documentclass[12pt]{article} \usepackage[utf8]{inputenc} -%\usepackage[margin=2cm]{geometry} +\usepackage[margin=2cm]{geometry} \title{Howework 1 -- Programming Fundamentals 3} \author{Claudio Maggioni} \begin{document} \maketitle +\tableofcontents \section{Exercise 1} \subsection{Question 1} -\texttt{MultipleUpdatesPerThread} is neither correct nor efficient. The reason for its uncorrectness is the unsynchronized access -of \emph{result}, which assigns unconsistent values to it: non-atomic evaluation of the statement \texttt{result += partialSum;} +\texttt{MultipleUpdatesPerThread} is neither correct nor efficient. The reason for its non-correctness is the unsynchronized access +of \emph{result}, which assigns non-consistent values to it: non-atomic evaluation of the statement \texttt{result += partialSum;} can make one thread evaluate the new value for \emph{result} before another has finished writing to it, thus producing incorrect results. @@ -26,7 +27,16 @@ results. \texttt{CollectingResults} is the only Thread-safe implementation because it is the only one not to use a static field to compute the final result. If multiple threads use anyone of the other classes concurrently, \emph{result} will be shared between the threads and all the results will be inconsistent. In order to solve this problem, either the entire \texttt{sum(...)} method must -be considered a critical section (defeating the point of concurrent access to the summing class) or the scope of result must be +be considered synchronised to \textit{this.class}, (defeating the point of concurrent access to the summing class) or the scope of result must be bound to the thread (e.g. by making \emph{result} either a private field and making the inner classes non-static, or by making it a local variable, as \texttt{CollectingResults} does). +\subsection{Question 7} +The slowest implementations are \texttt{MultipleUpdatesPerThreadSynch} and \linebreak[4] \texttt{MultipleUpdatesPerThreadAtomic} since, as discussed before for \textit{Question 1}, their execution is basically sequential since all the computation required for the sum is synchronized, making them even worse than a sequential algorithm due to the synchronization overhead. + +\texttt{SingleUpdatesPerThreadSynch}, \texttt{CollectingResults} and \texttt{SingleUpdatesPerThreadAtomic} are better, with the \textit{Atomic} version being marginally faster due to ISA-level optimization for the synchronization of \texttt{result}. They are faster than the previous couple since they actually make the computation of the sum parallel. This advantage holds only for a reasonable value for \texttt{NUM\_THREADS} (not too few, but not too close from below to the number of elements in the array). +\subsection{Question 8} +The sequential sum implementation always performs better than the \textit{MultipleUpdates*} implementations. + +In addition, this implementation is better performing than the other three implementations when +\texttt{NUM\_THREADS} is close to or bigger than the array length, since each thread in the parallel algorithms will sum few elements making the computation less parallel (since the final sum of \texttt{partialResult}s is sequential). \end{document} \ No newline at end of file