From 86cdf99f5b066ac43a31b7f4aa06e4740683afce Mon Sep 17 00:00:00 2001 From: cpopsa Date: Sat, 28 Jun 2014 15:03:03 +0300 Subject: [PATCH 1/2] Assigments 1-4 --- .../src/edu/vuum/mooca/SynchronizedQueue.java | 13 ++- .../src/edu/vuum/mocca/SimpleAtomicLong.java | 43 ++++++- .../src/edu/vuum/mocca/SimpleAtomicLong.java | 66 +++++++++-- .../src/edu/vuum/mocca/SimpleSemaphore.java | 43 ++++++- assignments/week-4-assignment-3/.classpath | 12 +- assignments/week-4-assignment-3/.project | 2 +- .../Assignment-Description.txt | 105 +++++++++++------- .../src/PingPongRight.java | 33 ++++-- .../src/SimpleSemaphore.java | 73 +++++++++--- ex/ThreadedDownload/.classpath | 2 +- 10 files changed, 298 insertions(+), 94 deletions(-) diff --git a/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java b/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java index c4ffb3c18..44ae66c3e 100644 --- a/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java +++ b/assignments/week-1-assignment-0/src/edu/vuum/mooca/SynchronizedQueue.java @@ -220,22 +220,25 @@ public static SynchronizedQueueResult testQueue(QueueAdapter queue) { // initialization below to create two Java Threads, one // that's passed the producerRunnable and the other that's // passed the consumerRunnable. - Thread consumer = null; - Thread producer = null; + Thread consumer = new Thread(consumerRunnable); + Thread producer = new Thread(producerRunnable); // TODO - you fill in here to start the threads. More // interesting results will occur if you start the // consumer first. - + consumer.start(); + producer.start(); // Give the Threads a chance to run before interrupting // them. Thread.sleep(100); // TODO - you fill in here to interrupt the threads. - + consumer.interrupt(); + producer.interrupt(); // TODO - you fill in here to wait for the threads to // exit. - + consumer.join(); + producer.join(); // Do some sanity checking to see if the Threads work as // expected. if (consumer == null diff --git a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java index b8851333a..7fad00e77 100644 --- a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java +++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java @@ -23,7 +23,7 @@ class SimpleAtomicLong // TODO -- you fill in here by replacing the null with an // initialization of ReentrantReadWriteLock. - private ReentrantReadWriteLock mRWLock = null; + private ReentrantReadWriteLock mRWLock = new ReentrantReadWriteLock(); /** * Creates a new SimpleAtomicLong with the given initial value. @@ -31,6 +31,7 @@ class SimpleAtomicLong public SimpleAtomicLong(long initialValue) { // TODO -- you fill in here + this.mValue = initialValue; } /** @@ -43,7 +44,12 @@ public long get() long value; // TODO -- you fill in here - + mRWLock.readLock().lock(); + try{ + value = mValue; + }finally{ + mRWLock.readLock().unlock(); + } return value; } @@ -57,6 +63,13 @@ public long decrementAndGet() long value = 0; // TODO -- you fill in here + mRWLock.writeLock().lock(); + try{ + mValue = mValue - 1; + value = mValue; + }finally{ + mRWLock.writeLock().unlock(); + } return value; } @@ -71,7 +84,14 @@ public long getAndIncrement() long value = 0; // TODO -- you fill in here - + mRWLock.writeLock().lock(); + try{ + value = mValue; + mValue = mValue + 1; + }finally{ + mRWLock.writeLock().unlock(); + } + return value; } @@ -85,7 +105,13 @@ public long getAndDecrement() long value = 0; // TODO -- you fill in here - + mRWLock.writeLock().lock(); + try{ + value = mValue; + mValue = mValue - 1; + }finally{ + mRWLock.writeLock().unlock(); + } return value; } @@ -99,7 +125,14 @@ public long incrementAndGet() long value = 0; // TODO -- you fill in here - + mRWLock.writeLock().lock(); + try{ + mValue = mValue + 1; + value = mValue; + }finally{ + mRWLock.writeLock().unlock(); + } + return value; } } diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java index 37f4d7fb4..7fad00e77 100644 --- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java +++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java @@ -1,5 +1,3 @@ -// Import the necessary Java synchronization and scheduling classes. - package edu.vuum.mocca; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -22,16 +20,18 @@ class SimpleAtomicLong /** * The ReentrantReadWriteLock used to serialize access to mValue. */ - // TODO - replace the null with the appropriate initialization: - private ReentrantReadWriteLock mRWLock = null; + + // TODO -- you fill in here by replacing the null with an + // initialization of ReentrantReadWriteLock. + private ReentrantReadWriteLock mRWLock = new ReentrantReadWriteLock(); /** * Creates a new SimpleAtomicLong with the given initial value. */ public SimpleAtomicLong(long initialValue) { - long value = 0; - // TODO - you fill in here + // TODO -- you fill in here + this.mValue = initialValue; } /** @@ -41,8 +41,15 @@ public SimpleAtomicLong(long initialValue) */ public long get() { - long value = 0; - // TODO - you fill in here, using a readLock() + long value; + + // TODO -- you fill in here + mRWLock.readLock().lock(); + try{ + value = mValue; + }finally{ + mRWLock.readLock().unlock(); + } return value; } @@ -54,7 +61,16 @@ public long get() public long decrementAndGet() { long value = 0; - // TODO - you fill in here, using a writeLock() + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + try{ + mValue = mValue - 1; + value = mValue; + }finally{ + mRWLock.writeLock().unlock(); + } + return value; } @@ -66,7 +82,16 @@ public long decrementAndGet() public long getAndIncrement() { long value = 0; - // TODO - you fill in here, using a writeLock() + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + try{ + value = mValue; + mValue = mValue + 1; + }finally{ + mRWLock.writeLock().unlock(); + } + return value; } @@ -78,7 +103,15 @@ public long getAndIncrement() public long getAndDecrement() { long value = 0; - // TODO - you fill in here, using a writeLock() + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + try{ + value = mValue; + mValue = mValue - 1; + }finally{ + mRWLock.writeLock().unlock(); + } return value; } @@ -90,7 +123,16 @@ public long getAndDecrement() public long incrementAndGet() { long value = 0; - // TODO - you fill in here, using a writeLock() + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + try{ + mValue = mValue + 1; + value = mValue; + }finally{ + mRWLock.writeLock().unlock(); + } + return value; } } diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java index a7a6e8df6..d11e28258 100644 --- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java +++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java @@ -17,19 +17,19 @@ public class SimpleSemaphore { * Define a ReentrantLock to protect the critical section. */ // TODO - you fill in here - + private ReentrantLock lock; /** * Define a ConditionObject to wait while the number of * permits is 0. */ // TODO - you fill in here - + private Condition condition; /** * Define a count of the number of available permits. */ // TODO - you fill in here. Make sure that this data member will // ensure its values aren't cached by multiple Threads.. - + private volatile int permits; /** * Constructor initialize the data members. */ @@ -37,6 +37,9 @@ public SimpleSemaphore (int permits, boolean fair) { // TODO - you fill in here + this.permits = permits; + lock = new ReentrantLock(fair); + condition = lock.newCondition(); } /** @@ -45,6 +48,15 @@ public SimpleSemaphore (int permits, */ public void acquire() throws InterruptedException { // TODO - you fill in here + lock.lockInterruptibly(); + try{ + while(permits == 0){ + condition.await(); + } + permits = permits - 1; + }finally{ + lock.unlock(); + } } /** @@ -53,6 +65,15 @@ public void acquire() throws InterruptedException { */ public void acquireUninterruptibly() { // TODO - you fill in here + lock.lock(); + try{ + while(permits == 0){ + condition.awaitUninterruptibly(); + } + permits = permits - 1; + }finally{ + lock.unlock(); + } } /** @@ -60,6 +81,13 @@ public void acquireUninterruptibly() { */ void release() { // TODO - you fill in here + lock.lock(); + try{ + permits = permits + 1; + condition.signalAll(); + }finally{ + lock.unlock(); + } } /** @@ -67,7 +95,14 @@ void release() { */ public int availablePermits(){ // TODO - you fill in here - return 0; // You will change this value. + int result = 0; + lock.lock(); + try{ + result = permits; + }finally{ + lock.unlock(); + } + return result; // You will change this value. } } diff --git a/assignments/week-4-assignment-3/.classpath b/assignments/week-4-assignment-3/.classpath index 18d70f02c..b8224469e 100644 --- a/assignments/week-4-assignment-3/.classpath +++ b/assignments/week-4-assignment-3/.classpath @@ -1,6 +1,10 @@ - - - - + + + + + + \ No newline at end of file diff --git a/assignments/week-4-assignment-3/.project b/assignments/week-4-assignment-3/.project index f5e4399a9..202df801d 100644 --- a/assignments/week-4-assignment-3/.project +++ b/assignments/week-4-assignment-3/.project @@ -14,4 +14,4 @@ org.eclipse.jdt.core.javanature - + \ No newline at end of file diff --git a/assignments/week-4-assignment-3/Assignment-Description.txt b/assignments/week-4-assignment-3/Assignment-Description.txt index c6452c2ed..add9d3d92 100644 --- a/assignments/week-4-assignment-3/Assignment-Description.txt +++ b/assignments/week-4-assignment-3/Assignment-Description.txt @@ -1,11 +1,15 @@ -Programming Assignment 1 +Week 4: Programming Assignment 3 + +Released Monday, June 2nd, 2014 +Due Monday, June 16th, 2014 In this assignment, you will implement a Java program that creates two instances of the PlayPingPongThread and then starts these thread instances to correctly alternate printing "Ping" and "Pong", -respectively, on the console display. This assignment also reuses the -SimpleSemaphore you implemented for the previous assignment, so make -sure it's working properly before attempting this assignment! +respectively, on the console display. This assignment also reuses the +SimpleSemaphore you implemented for the previous assignment, so please +apply any fixes motivated by watching the Virtual Office Hours video +of the instructor's solution(s). In this directory you'll find the PingPongRight.java class, which contains the skeleton Java code that you'll implement by completing @@ -16,17 +20,19 @@ DO NOT CHANGE THE OVERALL STRUCTURE OF THE SKELETON - just fill in the In particular, you'll need to do the following: . Implement the SimpleSemaphore class, which you should replace with - your working solution from the previous assignment. + your working solution from the previous assignment, after applying + any fixes motivated by watching the Virtual Office Hours video of + the instructor's solution(s). . Use your SimpleSemaphore to implement the PlayPingPongThread class and fix the problems with the earlier PingPongWrong solution, which is covered in this video: - Section 1: Module 2: Part 3: Motivating Java Synchronization and Scheduling Mechanisms + Section 1: Module 2: Part 3: Motivating Java Synchronization and Scheduling Mechanisms . Implement the PingPongRight class data members (including a Java CountDownLatch) and the main() function that uses the - SimpleSemaphore and CountDownLatch. The Java CountDownLatch class + SimpleSemaphore and CountDownLatch. The Java CountDownLatch class is covered in this video: Section 1: Module 2: Part 9: Java CountDownLatch @@ -34,7 +40,7 @@ In particular, you'll need to do the following: There are also relevant discussions about using Java CountDownLatches at these links: - http://javatechig.com/java/countdownlatch-and-java-concurrency-example + http://javatechig.com/java/countdownlatch-and-java-concurrency-example http://tutorials.jenkov.com/java-util-concurrent/countdownlatch.html . The PingPongRight.java program also uses various features of Java @@ -43,13 +49,19 @@ In particular, you'll need to do the following: Section 1: Module 2: Part 1: Overview of Java Threads (Part 1) Section 1: Module 2: Part 2: Overview of Java Threads (Part 2) -Note, at the moment, all these videos are available in the YouTube -playlist at - -https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4tbiFYip6tDNIEBRUDyPQK +. A more sophisticated example of a concurrent ping-pong program is + is shown in these videos: -When the 2014 POSA MOOC officially starts these videos will be -available at + Section 1: Module 2: Part 10: Java Synchronization and Scheduling Example (Part 1) + Section 1: Module 2: Part 11: Java Synchronization and Scheduling Example (Part 2) + + This programming assignment isn't as sophisticated (e.g., it doesn't + implement a framework and doesn't use as many GoF patterns), but I + suggest you watch these videos to learn more about how binary + semaphores can be used to correctly alternate printing "ping" and + "pong" from two Java Threads. + +These videos are available at https://class.coursera.org/posa-002/lecture @@ -60,7 +72,7 @@ in item #38 at the POSA MOOC FAQ available from http://www.courera.org/course/posa To compile this code you can either use the provided Eclipse project -or go into the src directory and simply type +or go into the src/edu/vuum/mooca directory and simply type % javac PingPongRight.java SimpleSemaphore.java @@ -68,33 +80,44 @@ and to run the resulting class file simply type % java PingPongRight -The correct solution should look exactly like this: +The correct solution when you run PingPongRight should look exactly +like this: Ready...Set...Go! -Ping!(1) -Pong!(1) -Ping!(2) -Pong!(2) -Ping!(3) -Pong!(3) -Ping!(4) -Pong!(4) -Ping!(5) -Pong!(5) -Ping!(6) -Pong!(6) -Ping!(7) -Pong!(7) -Ping!(8) -Pong!(8) -Ping!(9) -Pong!(9) -Ping!(10) -Pong!(10) +Ping! (1) + Pong! (1) +Ping! (2) + Pong! (2) +Ping! (3) + Pong! (3) +Ping! (4) + Pong! (4) +Ping! (5) + Pong! (5) +Ping! (6) + Pong! (6) +Ping! (7) + Pong! (7) +Ping! (8) + Pong! (8) +Ping! (9) + Pong! (9) +Ping! (10) + Pong! (10) Done! - - - - - +There is also a Unit Test Suite that will run the PingPongRightTest +file included in the test/edu/vuum/mooca directory for you at. When +you first open the project in Eclipse, you might see compile errors if +JUnit is not included in your build path. To fix these errors, open +SynchronizedQueueTest.java, hover over "org.junit," and click "Fix +project setup." Make sure "Add JUnit 4 library to the build path" is +selected and then click "OK." At this point, the compile errors +should disappear! + +Right click on the PingPongRightTest.java file in Eclipse and select +'Run As' -> 'JUnit Test'. When the assignment is complete, the test +should complete successfully. If the test passes a green-check mark +will appear next to the test in the JUnit view. As long as this JUnit +test "passes" successfully your program will be be consider "correct" +for the purposes of assessing this assignment. \ No newline at end of file diff --git a/assignments/week-4-assignment-3/src/PingPongRight.java b/assignments/week-4-assignment-3/src/PingPongRight.java index 53b8411d4..aabd5082d 100644 --- a/assignments/week-4-assignment-3/src/PingPongRight.java +++ b/assignments/week-4-assignment-3/src/PingPongRight.java @@ -1,6 +1,7 @@ // Import the necessary Java synchronization and scheduling classes. import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; /** * @class PingPongRight @@ -19,7 +20,7 @@ public class PingPongRight { /** * Latch that will be decremented each time a thread exits. */ - public static CountDownLatch latch = null; // TODO - You fill in here + public static CountDownLatch latch = new CountDownLatch(2); // TODO - You fill in here /** * @class PlayPingPongThread @@ -30,12 +31,18 @@ public class PingPongRight { */ public static class PlayPingPongThread extends Thread { + private final static int FIRST_SEMA = 0; + private final static int SECOND_SEMA = 1; /** * Constructor initializes the data member. */ - public PlayPingPongThread (/* TODO - You fill in here */) + public PlayPingPongThread (/* TODO - You fill in here */ + SimpleSemaphore firstSema, SimpleSemaphore secondSema, String mStringToPrint) { // TODO - You fill in here. + mSemaphores[FIRST_SEMA] = firstSema; + mSemaphores[SECOND_SEMA] = secondSema; + this.mStringToPrint = mStringToPrint; } /** @@ -46,6 +53,12 @@ public PlayPingPongThread (/* TODO - You fill in here */) public void run () { // TODO - You fill in here. + for (int loopsDone = 1; loopsDone <= mMaxIterations; ++loopsDone) { + mSemaphores[FIRST_SEMA].acquireUninterruptibly(); + System.out.println(mStringToPrint + "(" + loopsDone + ")"); + mSemaphores[SECOND_SEMA].release(); + } + latch.countDown(); } /** @@ -53,11 +66,13 @@ public void run () * iteration. */ // TODO - You fill in here. - + private String mStringToPrint; + /** * The two SimpleSemaphores use to alternate pings and pongs. */ // TODO - You fill in here. + private SimpleSemaphore mSemaphores[] = new SimpleSemaphore[2]; } /** @@ -69,15 +84,19 @@ public static void main(String[] args) { // alternation between threads. // TODO - You fill in here. - + SimpleSemaphore pingSema = new SimpleSemaphore(1, true); + SimpleSemaphore pongSema = new SimpleSemaphore(0, true); + System.out.println("Ready...Set...Go!"); // Create the ping and pong threads, passing in the string // to print and the appropriate SimpleSemaphores. PlayPingPongThread ping = - new PlayPingPongThread(/* TODO - You fill in here */); + new PlayPingPongThread(/* TODO - You fill in here */ + pingSema, pongSema, "ping"); PlayPingPongThread pong = - new PlayPingPongThread(/* TODO - You fill in here */); + new PlayPingPongThread(/* TODO - You fill in here */ + pongSema, pingSema, "pong"); // Initiate the ping and pong threads, which will call the // run() hook method. @@ -90,7 +109,7 @@ public static void main(String[] args) { // TODO - replace replace the following line with a // CountDownLatch barrier synchronizer call that waits for // both threads to finish. - throw new java.lang.InterruptedException(); + latch.await(); } catch (java.lang.InterruptedException e) {} diff --git a/assignments/week-4-assignment-3/src/SimpleSemaphore.java b/assignments/week-4-assignment-3/src/SimpleSemaphore.java index d3c534373..ebcbd51f9 100644 --- a/assignments/week-4-assignment-3/src/SimpleSemaphore.java +++ b/assignments/week-4-assignment-3/src/SimpleSemaphore.java @@ -11,6 +11,23 @@ * "NonFair" semaphore semantics, just liked Java Semaphores. */ public class SimpleSemaphore { + /** + * Define a ReentrantLock to protect the critical section. + */ + // TODO - you fill in here + private ReentrantLock lock; + /** + * Define a ConditionObject to wait while the number of + * permits is 0. + */ + // TODO - you fill in here + private Condition condition; + /** + * Define a count of the number of available permits. + */ + // TODO - you fill in here. Make sure that this data member will + // ensure its values aren't cached by multiple Threads.. + private volatile int permits; /** * Constructor initialize the data members. */ @@ -18,6 +35,9 @@ public SimpleSemaphore (int permits, boolean fair) { // TODO - you fill in here + this.permits = permits; + lock = new ReentrantLock(fair); + condition = lock.newCondition(); } /** @@ -26,6 +46,15 @@ public SimpleSemaphore (int permits, */ public void acquire() throws InterruptedException { // TODO - you fill in here + lock.lockInterruptibly(); + try{ + while(permits == 0){ + condition.await(); + } + permits = permits - 1; + }finally{ + lock.unlock(); + } } /** @@ -34,6 +63,15 @@ public void acquire() throws InterruptedException { */ public void acquireUninterruptibly() { // TODO - you fill in here + lock.lock(); + try{ + while(permits == 0){ + condition.awaitUninterruptibly(); + } + permits = permits - 1; + }finally{ + lock.unlock(); + } } /** @@ -41,21 +79,28 @@ public void acquireUninterruptibly() { */ void release() { // TODO - you fill in here + lock.lock(); + try{ + permits = permits + 1; + condition.signalAll(); + }finally{ + lock.unlock(); + } } - - /** - * Define a ReentrantLock to protect the critical section. - */ - // TODO - you fill in here - - /** - * Define a ConditionObject to wait while the number of - * permits is 0. - */ - // TODO - you fill in here - + /** - * Define a count of the number of available permits. + * Return the number of permits available. */ - // TODO - you fill in here + public int availablePermits(){ + // TODO - you fill in here + int result = 0; + lock.lock(); + try{ + result = permits; + }finally{ + lock.unlock(); + } + return result; // You will change this value. + } } + diff --git a/ex/ThreadedDownload/.classpath b/ex/ThreadedDownload/.classpath index 0b0840834..d57ec0251 100644 --- a/ex/ThreadedDownload/.classpath +++ b/ex/ThreadedDownload/.classpath @@ -1,7 +1,7 @@ - + From c03513b26fe8ec263077192efe7ec751e2688759 Mon Sep 17 00:00:00 2001 From: cpopsa Date: Sat, 28 Jun 2014 15:12:44 +0300 Subject: [PATCH 2/2] Week 4 --- .../src/edu/vuum/mocca/PingPongRight.java | 312 +++++++++--------- .../src/edu/vuum/mocca/SimpleSemaphore.java | 94 ++++-- .../edu/vuum/mocca/PingPongRightTest.java | 144 ++++---- 3 files changed, 305 insertions(+), 245 deletions(-) diff --git a/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java b/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java index 4fd24024f..142b72ae4 100644 --- a/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java @@ -1,157 +1,175 @@ package edu.vuum.mocca; + // Import the necessary Java synchronization and scheduling classes. import java.util.concurrent.CountDownLatch; /** * @class PingPongRight - * + * * @brief This class implements a Java program that creates two - * instances of the PlayPingPongThread and start these thread - * instances to correctly alternate printing "Ping" and "Pong", - * respectively, on the console display. + * instances of the PlayPingPongThread and start these thread + * instances to correctly alternate printing "Ping" and "Pong", + * respectively, on the console display. */ public class PingPongRight { - /** - * Number of iterations to run the test program. - */ - public final static int mMaxIterations = 10; - - /** - * Latch that will be decremented each time a thread exits. - */ - public static CountDownLatch mLatch = null; - - /** - * @class PlayPingPongThread - * - * @brief This class implements the ping/pong processing algorithm - * using the SimpleSemaphore to alternate printing "ping" - * and "pong" to the console display. - */ - public static class PlayPingPongThread extends Thread { - /** - * Constants to distinguish between ping and pong - * SimpleSemaphores, if you choose to use an array of - * SimpleSemaphores. If you don't use this implementation - * feel free to remove these constants. - */ - private final static int FIRST_SEMA = 0; - private final static int SECOND_SEMA = 1; - - /** - * Maximum number of loop iterations. - */ - private int mMaxLoopIterations = 0; - - /** - * String to print (either "ping!" or "pong"!) for each - * iteration. - */ - // TODO - You fill in here. - - /** - * Two SimpleSemaphores use to alternate pings and pongs. You - * can use an array of SimpleSemaphores or just define them as - * two data members. - */ - // TODO - You fill in here. - - /** - * Constructor initializes the data member(s). - */ - public PlayPingPongThread(String stringToPrint, - SimpleSemaphore semaphoreOne, - SimpleSemaphore semaphoreTwo, - int maxIterations) { - // TODO - You fill in here. - } - - /** - * Main event loop that runs in a separate thread of control - * and performs the ping/pong algorithm using the - * SimpleSemaphores. - */ - public void run() { - /** - * This method runs in a separate thread of control and - * implements the core ping/pong algorithm. - */ - - // TODO - You fill in here. - } - - /** - * Method for acquiring the appropriate SimpleSemaphore. - */ - private void acquire() { - // TODO fill in here - } - - /** - * Method for releasing the appropriate SimpleSemaphore. - */ - private void release() { - // TODO fill in here - } - } - - /** - * The method that actually runs the ping/pong program. - */ - public static void process(String startString, - String pingString, - String pongString, - String finishString, - int maxIterations) throws InterruptedException { - - // TODO initialize this by replacing null with the appropriate - // constructor call. - mLatch = null; - - // Create the ping and pong SimpleSemaphores that control - // alternation between threads. - - // TODO - You fill in here, make pingSema start out unlocked. - SimpleSemaphore pingSema = null; - // TODO - You fill in here, make pongSema start out locked. - SimpleSemaphore pongSema = null; - - System.out.println(startString); - - // Create the ping and pong threads, passing in the string to - // print and the appropriate SimpleSemaphores. - PlayPingPongThread ping = new PlayPingPongThread(/* - * TODO - You fill in - * here - */); - PlayPingPongThread pong = new PlayPingPongThread(/* - * TODO - You fill in - * here - */); - - // TODO - Initiate the ping and pong threads, which will call - // the run() hook method. - - // TODO - replace the following line with a barrier - // synchronizer call to mLatch that waits for both threads to - // finish. - throw new java.lang.InterruptedException(); - - System.out.println(finishString); - } - - /** - * The main() entry point method into PingPongRight program. - * - * @throws InterruptedException - */ - public static void main(String[] args) throws InterruptedException { - process("Ready...Set...Go!", - "Ping! ", - " Pong! ", - "Done!", - mMaxIterations); - } -} - + /** + * Number of iterations to run the test program. + */ + public final static int mMaxIterations = 10; + + /** + * Latch that will be decremented each time a thread exits. + */ + public static CountDownLatch mLatch = null; + + /** + * @class PlayPingPongThread + * + * @brief This class implements the ping/pong processing algorithm + * using the SimpleSemaphore to alternate printing "ping" + * and "pong" to the console display. + */ + public static class PlayPingPongThread extends Thread { + /** + * Constants to distinguish between ping and pong + * SimpleSemaphores, if you choose to use an array of + * SimpleSemaphores. If you don't use this implementation + * feel free to remove these constants. + */ + private final static int FIRST_SEMA = 0; + private final static int SECOND_SEMA = 1; + + /** + * Maximum number of loop iterations. + */ + private int mMaxLoopIterations = 0; + + /** + * String to print (either "ping!" or "pong"!) for each + * iteration. + */ + // TODO - You fill in here. + private String mStringToPrint; + + /** + * Two SimpleSemaphores use to alternate pings and pongs. You + * can use an array of SimpleSemaphores or just define them as + * two data members. + */ + // TODO - You fill in here. + private SimpleSemaphore mSemaphores[] = new SimpleSemaphore[2]; + + /** + * Constructor initializes the data member(s). + */ + public PlayPingPongThread(String stringToPrint, + SimpleSemaphore semaphoreOne, + SimpleSemaphore semaphoreTwo, + int maxIterations) { + // TODO - You fill in here. + mStringToPrint = stringToPrint; + mSemaphores[FIRST_SEMA] = semaphoreOne; + mSemaphores[SECOND_SEMA] = semaphoreTwo; + mMaxLoopIterations = maxIterations; + } + + /** + * Main event loop that runs in a separate thread of control + * and performs the ping/pong algorithm using the + * SimpleSemaphores. + */ + public void run() { + /** + * This method runs in a separate thread of control and + * implements the core ping/pong algorithm. + */ + + // TODO - You fill in here. + for (int loopsDone = 1; loopsDone <= mMaxLoopIterations; ++loopsDone) { + acquire(); + System.out.println(mStringToPrint + "(" + loopsDone + ")"); + release(); + } + mLatch.countDown(); + } + + /** + * Method for acquiring the appropriate SimpleSemaphore. + */ + private void acquire() { + // TODO fill in here + mSemaphores[FIRST_SEMA].acquireUninterruptibly(); + } + + /** + * Method for releasing the appropriate SimpleSemaphore. + */ + private void release() { + // TODO fill in here + mSemaphores[SECOND_SEMA].release(); + } + } + + /** + * The method that actually runs the ping/pong program. + */ + public static void process(String startString, + String pingString, + String pongString, + String finishString, + int maxIterations) throws InterruptedException { + + // TODO initialize this by replacing null with the appropriate + // constructor call. + mLatch = new CountDownLatch(2); + + // Create the ping and pong SimpleSemaphores that control + // alternation between threads. + + // TODO - You fill in here, make pingSema start out unlocked. + SimpleSemaphore pingSema = new SimpleSemaphore(1, true); + // TODO - You fill in here, make pongSema start out locked. + SimpleSemaphore pongSema = new SimpleSemaphore(0, true); + + System.out.println(startString); + + // Create the ping and pong threads, passing in the string to + // print and the appropriate SimpleSemaphores. + PlayPingPongThread ping = new PlayPingPongThread(/* + * TODO - You fill in + * here + */ + pingString, pingSema, pongSema, maxIterations); + PlayPingPongThread pong = new PlayPingPongThread(/* + * TODO - You fill in + * here + */ + pongString, pongSema, pingSema, maxIterations); + + // TODO - Initiate the ping and pong threads, which will call + // the run() hook method. + ping.start(); + pong.start(); + + // TODO - replace the following line with a barrier + // synchronizer call to mLatch that waits for both threads to + // finish. + mLatch.await(); + + System.out.println(finishString); + } + + /** + * The main() entry point method into PingPongRight program. + * + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + process("Ready...Set...Go!", + "Ping! ", + " Pong! ", + "Done!", + mMaxIterations); + } +} \ No newline at end of file diff --git a/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java index 5e473adf6..d11e28258 100644 --- a/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java @@ -1,66 +1,108 @@ package edu.vuum.mocca; -import java.util.concurrent.locks.Condition; + import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.Condition; /** * @class SimpleSemaphore - * - * @brief This class provides a simple counting semaphore implementation using - * Java a ReentrantLock and a ConditionObject (which is accessed via a - * Condition). It must implement both "Fair" and "NonFair" semaphore - * semantics, just liked Java Semaphores. + * + * @brief This class provides a simple counting semaphore + * implementation using Java a ReentrantLock and a + * ConditionObject. It must implement both "Fair" and + * "NonFair" semaphore semantics, just liked Java Semaphores. */ public class SimpleSemaphore { /** * Define a ReentrantLock to protect the critical section. */ // TODO - you fill in here - + private ReentrantLock lock; /** - * Define a Condition that waits while the number of permits is 0. + * Define a ConditionObject to wait while the number of + * permits is 0. */ // TODO - you fill in here - + private Condition condition; /** * Define a count of the number of available permits. */ - // TODO - you fill in here. Make sure that this data member will + // TODO - you fill in here. Make sure that this data member will // ensure its values aren't cached by multiple Threads.. - - public SimpleSemaphore(int permits, boolean fair) { - // TODO - you fill in here to initialize the SimpleSemaphore, - // making sure to allow both fair and non-fair Semaphore - // semantics. + private volatile int permits; + /** + * Constructor initialize the data members. + */ + public SimpleSemaphore (int permits, + boolean fair) + { + // TODO - you fill in here + this.permits = permits; + lock = new ReentrantLock(fair); + condition = lock.newCondition(); } /** - * Acquire one permit from the semaphore in a manner that can be - * interrupted. + * Acquire one permit from the semaphore in a manner that can + * be interrupted. */ public void acquire() throws InterruptedException { - // TODO - you fill in here. + // TODO - you fill in here + lock.lockInterruptibly(); + try{ + while(permits == 0){ + condition.await(); + } + permits = permits - 1; + }finally{ + lock.unlock(); + } } /** - * Acquire one permit from the semaphore in a manner that cannot be - * interrupted. + * Acquire one permit from the semaphore in a manner that + * cannot be interrupted. */ public void acquireUninterruptibly() { - // TODO - you fill in here. + // TODO - you fill in here + lock.lock(); + try{ + while(permits == 0){ + condition.awaitUninterruptibly(); + } + permits = permits - 1; + }finally{ + lock.unlock(); + } } /** * Return one permit to the semaphore. */ void release() { - // TODO - you fill in here. + // TODO - you fill in here + lock.lock(); + try{ + permits = permits + 1; + condition.signalAll(); + }finally{ + lock.unlock(); + } } - + /** * Return the number of permits available. */ - public int availablePermits() { - // TODO - you fill in here to return the correct result - return 0; + public int availablePermits(){ + // TODO - you fill in here + int result = 0; + lock.lock(); + try{ + result = permits; + }finally{ + lock.unlock(); + } + return result; // You will change this value. } } + diff --git a/assignments/week-4-assignment-3/test/edu/vuum/mocca/PingPongRightTest.java b/assignments/week-4-assignment-3/test/edu/vuum/mocca/PingPongRightTest.java index 5148fba59..964fb0e37 100644 --- a/assignments/week-4-assignment-3/test/edu/vuum/mocca/PingPongRightTest.java +++ b/assignments/week-4-assignment-3/test/edu/vuum/mocca/PingPongRightTest.java @@ -12,89 +12,89 @@ /** * @class PingPongRightTest - * + * * @brief This JUnit test checks the PingPong program to make sure it's working - * properly. + * properly. */ public class PingPongRightTest { - /* - * These data members are used to capture [ - * System.out.println() ] for testing. - */ - private final ByteArrayOutputStream outContent = - new ByteArrayOutputStream(); - private final ByteArrayOutputStream errContent = - new ByteArrayOutputStream(); + /* + * These data members are used to capture [ + * System.out.println() ] for testing. + */ + private final ByteArrayOutputStream outContent = + new ByteArrayOutputStream(); + private final ByteArrayOutputStream errContent = + new ByteArrayOutputStream(); - /* - * Setup the output Capturing. - */ - @Before - public void setUpStreams() { - System.setOut(new PrintStream(outContent)); - System.setErr(new PrintStream(errContent)); - } + /* + * Setup the output Capturing. + */ + @Before + public void setUpStreams() { + System.setOut(new PrintStream(outContent)); + System.setErr(new PrintStream(errContent)); + } - /* - * Tear-down the output Capturing. - */ - @After - public void cleanUpStreams() { - System.setOut(null); - System.setErr(null); - } + /* + * Tear-down the output Capturing. + */ + @After + public void cleanUpStreams() { + System.setOut(null); + System.setErr(null); + } - /* - * Test the process(...) logic/accuracy - * - * Gives some helpful error outputs for some simple error states. - */ - @Test(timeout = 3000) - // This test will only run for 3000ms => 3 seconds, otherwise if fails - public void test() throws InterruptedException, IOException { - for (int i = 0; i < 10; i++) { - PingPongRight.process("start", "a", "b", "end", 10); - String outResults = outContent.toString(); + /* + * Test the process(...) logic/accuracy + * + * Gives some helpful error outputs for some simple error states. + */ + @Test(timeout = 3000) + // This test will only run for 3000ms => 3 seconds, otherwise if fails + public void test() throws InterruptedException, IOException { + for (int i = 0; i < 10; i++) { + PingPongRight.process("start", "a", "b", "end", 10); + String outResults = outContent.toString(); - if (outResults == null || outResults.length() == 0) { - fail("No output at all."); - } + if (outResults == null || outResults.length() == 0) { + fail("No output at all."); + } - //We need to split things up for Windows and UNIX due to - //differences in the way that newlines are handled. - boolean windowsTrue = outResults.equals(testResultWindows); - boolean unixTrue = outResults.equals(testResultUnix); - boolean pingAllFirstTrue = outResults.equals(pingAllFirst); - boolean pongAllFirstTrue = outResults.equals(pongAllFirst); + //We need to split things up for Windows and UNIX due to + //differences in the way that newlines are handled. + boolean windowsTrue = outResults.equals(testResultWindows); + boolean unixTrue = outResults.equals(testResultUnix); + boolean pingAllFirstTrue = outResults.equals(pingAllFirst); + boolean pongAllFirstTrue = outResults.equals(pongAllFirst); - if (errContent.toString().length() != 0) - fail("There was error text."); + if (errContent.toString().length() != 0) + fail("There was error text."); - if (pingAllFirstTrue) - fail("Ping Thread completed before Pong started."); + if (pingAllFirstTrue) + fail("Ping Thread completed before Pong started."); - if (pongAllFirstTrue) - fail("Pong Thread completed before Ping started."); + if (pongAllFirstTrue) + fail("Pong Thread completed before Ping started."); - if (!(windowsTrue || unixTrue)) - fail("Output was wrong.\n" - + "--- Received output ---\n" - + outResults - + "--- Expected output ---\n" - + testResultWindows); + if (!(windowsTrue || unixTrue)) + fail("Output was wrong.\n" + + "--- Received output ---\n" + + outResults + + "--- Expected output ---\n" + + testResultWindows); - outContent.reset(); - } - } + outContent.reset(); + } + } - // This is what should be output \n was replaced for visible - // endlines for inclusion into single line. - String testResultUnix = - "start\na(1)\nb(1)\na(2)\nb(2)\na(3)\nb(3)\na(4)\nb(4)\na(5)\nb(5)\na(6)\nb(6)\na(7)\nb(7)\na(8)\nb(8)\na(9)\nb(9)\na(10)\nb(10)\nend\n"; - String testResultWindows = - "start\r\na(1)\r\nb(1)\r\na(2)\r\nb(2)\r\na(3)\r\nb(3)\r\na(4)\r\nb(4)\r\na(5)\r\nb(5)\r\na(6)\r\nb(6)\r\na(7)\r\nb(7)\r\na(8)\r\nb(8)\r\na(9)\r\nb(9)\r\na(10)\r\nb(10)\r\nend\r\n"; - String pingAllFirst = - "start\r\na(1)\r\nb(1)\r\na(2)\r\na(3)\r\na(4)\r\na(5)\r\na(6)\r\na(7)\r\na(8)\r\na(9)\r\na(10)\r\nb(2)\r\nb(3)\r\nb(4)\r\nb(5)\r\nb(6)\r\nb(8)\r\nb(7)\r\nb(9)\r\nb(10)\r\nend\r\n"; - String pongAllFirst = - "start\r\nb(1)\r\nb(2)\r\nb(3)\r\nb(4)\r\nb(5)\r\nb(6)\r\nb(8)\r\nb(7)\r\nb(9)\r\nb(10)\r\na(1)\r\na(2)\r\na(3)\r\na(4)\r\na(5)\r\na(6)\r\na(7)\r\na(8)\r\na(9)\r\na(10)\r\nend\r\n"; -} + // This is what should be output \n was replaced for visible + // endlines for inclusion into single line. + String testResultUnix = + "start\na(1)\nb(1)\na(2)\nb(2)\na(3)\nb(3)\na(4)\nb(4)\na(5)\nb(5)\na(6)\nb(6)\na(7)\nb(7)\na(8)\nb(8)\na(9)\nb(9)\na(10)\nb(10)\nend\n"; + String testResultWindows = + "start\r\na(1)\r\nb(1)\r\na(2)\r\nb(2)\r\na(3)\r\nb(3)\r\na(4)\r\nb(4)\r\na(5)\r\nb(5)\r\na(6)\r\nb(6)\r\na(7)\r\nb(7)\r\na(8)\r\nb(8)\r\na(9)\r\nb(9)\r\na(10)\r\nb(10)\r\nend\r\n"; + String pingAllFirst = + "start\r\na(1)\r\nb(1)\r\na(2)\r\na(3)\r\na(4)\r\na(5)\r\na(6)\r\na(7)\r\na(8)\r\na(9)\r\na(10)\r\nb(2)\r\nb(3)\r\nb(4)\r\nb(5)\r\nb(6)\r\nb(8)\r\nb(7)\r\nb(9)\r\nb(10)\r\nend\r\n"; + String pongAllFirst = + "start\r\nb(1)\r\nb(2)\r\nb(3)\r\nb(4)\r\nb(5)\r\nb(6)\r\nb(8)\r\nb(7)\r\nb(9)\r\nb(10)\r\na(1)\r\na(2)\r\na(3)\r\na(4)\r\na(5)\r\na(6)\r\na(7)\r\na(8)\r\na(9)\r\na(10)\r\nend\r\n"; +} \ No newline at end of file