Attempt 1

This commit is contained in:
Jake Hillion 2019-11-07 22:31:15 +00:00
parent b63be079f7
commit b9cf360b29
4 changed files with 145 additions and 21 deletions

View File

@ -36,8 +36,12 @@ public class BankSimulator {
}
public void transferTo(BankAccount b, int amount) {
balance -= amount;
b.balance += amount;
synchronized (this.acc > b.acc ? this : b) {
synchronized (this.acc > b.acc ? b : this) {
balance -= amount;
b.balance += amount;
}
}
}
}

View File

@ -22,6 +22,7 @@ public class QueueTest {
private int sent = 0;
public void run() {
// Adds 50000 messages to the queue, each containing the string representation of the numbers counting up
for (int i = 0; i < 50000; ++i) {
q.put("" + i);
sent++;
@ -65,15 +66,18 @@ public class QueueTest {
}
public void run() {
// Start the requested number of consumer threads
for (Consumer c : consumers) {
c.start();
}
// Start the requested number of producer threads
for (Producer p : producers) {
p.start();
}
// Join each producer thread - this awaits completion of each thread by joining this thread to its execution
// This loops awaits the completion of all producers
for (Producer p : producers) {
try {
p.join();
@ -83,6 +87,7 @@ public class QueueTest {
}
q.put("EOF");
// terminate join at 10 secs since EOF marker may get lost
// perform the same waiting for each consumer
for (Consumer c : consumers) {
try {
c.join(10000);
@ -91,6 +96,7 @@ public class QueueTest {
}
}
// Compare the total number of messages received to the total number sent
int recv = 0;
for (Consumer consumer : consumers) {
recv += consumer.numberConsumed();
@ -109,10 +115,10 @@ public class QueueTest {
new QueueTest(new UnsafeMessageQueue<String>(), 1, 3).run();
new QueueTest(new UnsafeMessageQueue<String>(), 3, 3).run();
// System.out.println("** SAFE ** ");
// new QueueTest(new SafeMessageQueue<String>(), 1, 1).run();
// new QueueTest(new SafeMessageQueue<String>(), 3, 1).run();
// new QueueTest(new SafeMessageQueue<String>(), 1, 3).run();
// new QueueTest(new SafeMessageQueue<String>(), 3, 3).run();
System.out.println("** SAFE ** ");
new QueueTest(new SafeMessageQueue<String>(), 1, 1).run();
new QueueTest(new SafeMessageQueue<String>(), 3, 1).run();
new QueueTest(new SafeMessageQueue<String>(), 1, 3).run();
new QueueTest(new SafeMessageQueue<String>(), 3, 3).run();
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2019 Andrew Rice <acr31@cam.ac.uk>, Alastair Beresford <arb33@cam.ac.uk>, J.S. Hillion
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.ac.cam.jsh77.fjava.tick3;
public class SafeMessageQueue<T> implements MessageQueue<T> {
private Link<T> first = null;
private Link<T> last = null;
public synchronized void put(T val) {
Link<T> link = new Link<>(val);
if (first == null && last == null) {
first = last = link;
} else {
last.next = link;
last = link;
}
this.notify();
}
public synchronized T take() {
while (first == null) { // use a loop to block thread until data is available
try {
this.wait();
} catch (InterruptedException ie) {
// QUESTION: what causes this exception to be thrown? and what should
// you do with it ideally?
/*
The exception is thrown when the thread is interrupted while blocking (sleeping here).
To correctly support interrupts, the Thread should exit cleanly. In this case, the best way to do that
is to return null.
*/
return null;
}
}
Link<T> oldFirst = first;
if (last == oldFirst) last = null;
first = oldFirst.next;
return oldFirst.val;
}
@Override
public String toString() {
return "UnsafeMessageQueue{" +
"first=" + first +
", last=" + last +
'}';
}
private static class Link<L> {
L val;
Link<L> next;
Link(L val) {
this.val = val;
this.next = null;
}
@Override
public String toString() {
return "Link{" +
"val=" + val +
", next=" + next +
'}';
}
}
}

View File

@ -17,16 +17,6 @@
package uk.ac.cam.jsh77.fjava.tick3;
public class UnsafeMessageQueue<T> implements MessageQueue<T> {
private static class Link<L> {
L val;
Link<L> next;
Link(L val) {
this.val = val;
this.next = null;
}
}
private Link<T> first = null;
private Link<T> last = null;
@ -34,6 +24,13 @@ public class UnsafeMessageQueue<T> implements MessageQueue<T> {
// TODO: given a new "val", create a new Link<T>
// element to contain it and update "first" and
// "last" as appropriate
Link<T> link = new Link<>(val);
if (first == null && last == null) {
first = last = link;
} else {
last.next = link;
last = link;
}
}
public T take() {
@ -44,10 +41,44 @@ public class UnsafeMessageQueue<T> implements MessageQueue<T> {
// Ignored exception
// TODO: what causes this exception to be thrown? and what should
// you do with it ideally?
/*
The exception is thrown when the thread is interrupted while blocking (sleeping here).
To correctly support interrupts, the Thread should exit cleanly. In this case, the best way to do that
is to return null.
*/
return null;
}
}
// TODO: retrieve "val" from "first", update "first" to refer
// to next element in list (if any). Return "val"
return null;
Link<T> oldFirst = first;
if (last == oldFirst) last = null;
first = oldFirst.next;
return oldFirst.val;
}
@Override
public String toString() {
return "UnsafeMessageQueue{" +
"first=" + first +
", last=" + last +
'}';
}
private static class Link<L> {
L val;
Link<L> next;
Link(L val) {
this.val = val;
this.next = null;
}
@Override
public String toString() {
return "Link{" +
"val=" + val +
", next=" + next +
'}';
}
}
}