TwoPhaseLocking
This question concerns Two Phase Locking (2PL). For each schedule, say if there is either a conflict or a violation and provide a motivation. If there are conflicts/violations, show how such a schedule changes after the introduction of eXclusive/Shared locks; otherwise, propose a possible scheduling where such problems may occur. Last, implement the two threads in Java exhibiting the correct behaviour using ReadWriteLocks.
这个问题涉及两阶段锁定(2 PL)。对于每个时间表,如果有冲突或违反,并提供一个动机。如果存在冲突/违规,请说明在引入互斥锁/共享锁后,这样的调度如何更改;否则,请提出可能发生此类问题的可能调度。最后,在Java中实现两个线程,使用ReadWriteLocks展示正确的行为。
Please remember the following notation for your pseudocode part:
• W1(x) for Write1(x), or a write operation on x performed by the first thread;
• R2(x) for Read2(x), or a read operation on x performed by the second thread;
• X1(x) for an exclusive lock on x performed by the first thread
• S2(x) for a shared lock on x performed by the second thread.
• commit1() for a commit performed by the first thread
• abort2() for an abort on error performed by the second thread.
- [20] W1(X); R2(X); abort1(); commit2();
- [20] W1(X++); R2(X); W1(X++); R2(X); W1(X++); commit1(); commit2();
请记住以下伪代码部分的符号:
· W1(x),用于Write 1(x),或由第一线程执行的对x的写操作;
· R2(x),用于Read 2(x),或者由第二线程执行的对x的读取操作;
· X1(x),表示第一个线程对x执行的独占锁
· S2(x),用于由第二线程执行的x上的共享锁。
·commit 1(),用于由第一线程执行的提交
·abort 2(),用于由第二线程执行的错误中止。 - [20]W1(X); R2(X); abort(); commit();
- [20]W1(X++); R2(X); W1(X++); R2(X); W1(X++); commit1(); commit2();
Exercise 1
[Please remember that, in these exercises, fixing the concurrency problem does not require changing the set of operations associated to a thread, while always preferring to preserve the same order of operations enforced by the first process applying the concurrency controls, while the second-following process might have to wait for the operations’ completion.]
We have a Dirty Read with a Write-Read Conflict [In addition to this, you should also motivate why, by referring to the specific operations within the threads. An example for doing so is given in the next exercise.]
[请记住,在这些练习中,修复并发问题不需要更改与线程关联的操作集,同时总是倾向于保留由应用并发控制的第一个进程执行的相同操作顺序,而第二个进程可能必须等待操作完成。
我们有一个带有读写冲突的脏读[除此之外,您还应该通过引用线程中的特定操作来激励原因。在下一个练习中给出了这样做的示例。]
X1 (X); W1(X); S2(X); [T2 Waits] abort1(); [T2 Wakes] R2 (X); commit2();
final ReentrantReadWriteLock lockForVariableX = new ReentrantReadWriteLock()
volatile long X = 10; // Global variable, arbitrary value
//The threads
var t1 = new Thread(() -> {
lockForVariableX.writeLock().lock();
var tmpX = X; // Performing the operations over a local copy, so we can roll-back on abort tmpX = 23; // An arbitrary write operation: an increment/decrement is also fine
// Aborting! This requires to roll-back to the previous variable: as everything was only performed locally and there was no explicit write operations on the global variable, I can just commit by locking without the need for updating the value.
lockForVariableX.writeLock().unlock();
});
var t2 = new Thread(() -> {
lockForVariableX.writeLock().lock();
var tmpX = X;
System.out.println(tmpX); // reading the value on a local copy is fine as a simple read operation:you can also print on the terminal if you want, but the above line is more than enough!
lockForVariableX.writeLock().unlock();
});
Exercise 2
We have a Phantom with Write-Read conflicts, because T2 always reads different values for x.
X1(x); W1(x++); S2(x); [T2 Waits] W1(x++); W1(x++); commit1(); [T2 Wakes] R2(x);
R2(x); S2 (y); R2(y); commit2();
final ReentrantReadWriteLock lockForVariableX = new ReentrantReadWriteLock();
final ReentrantReadWriteLock lockForVariableY = new ReentrantReadWriteLock();
volatile long X = 10, Y = 20; // Global variable, arbitrary value
var t1 = new Thread(() -> {
lockForVariableX.writeLock().lock();
var tmpX = X; // locally storing the variable
tmpX++; // first write operation
tmpX++; // second write operation
tmpX++; // Third write operation
X = tmpX; // At commit time, updating the global value of X
lockForVariableX.writeLock().unlock();
});
var t2 = new Thread(() -> {
lockForVariableX.writeLock().lock();
var tmpX = X;
System.out.println(tmpX); // reading the value on a local copy is fine as a simple read operation:you can also print on the terminal if you want, but the above line is more than enough!
System.out.println(tmpX); // Doing tmpX = X is also fine, as we are within locks!
lockForVariableY.writeLock().lock();
var tmpY = Y; // Read operation
lockForVariableY.writeLock().unlock(); // Always remember to always unlock in the reverse order of locking!
// You are not required to update the global variable, as this process never updated such a variable, so no updates are required to be stored globally before the release
lockForVariableX.writeLock().unlock();
});
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class TwoPL {
long X, Y;
public TwoPL() {
X = 10;
Y = 20;
}
public void ex1() throws InterruptedException {
final ReentrantReadWriteLock lockForVariableX = new
ReentrantReadWriteLock();
var t1 = new Thread(() -> {
lockForVariableX.writeLock().lock();
long localX = 23;
X = localX;
// abort! Restoring the original value
X = 10;
lockForVariableX.writeLock().unlock();
});
var t2 = new Thread(() -> {
lockForVariableX.readLock().lock();
long localX = X;
System.out.println(localX); // Always reading the correct value, 10! The
print is not required at the exam
lockForVariableX.readLock().unlock(); // commit!
});
t1.start(); t2.start();
t1.join(); t2.join();
}
public void ex2() {
ReentrantReadWriteLock lockForVariableX = new ReentrantReadWriteLock(); //
implicitely final
ReentrantReadWriteLock lockForVariableY = new ReentrantReadWriteLock(); //
implicitely final
var t1 = new Thread(() -> {
lockForVariableX.writeLock().lock();
// Simulating a non-atomic increment
var localX = X;
localX = localX +1;
X = localX;
// Second increment
localX = X;
localX = localX +1;
X = localX;
// Third increment
localX = X;
localX = localX +1;
X = localX;
//commit
lockForVariableX.writeLock().unlock();
});
var t2 = new Thread(() -> {
lockForVariableX.readLock().lock();
// First read
var localX = X;
System.out.println(localX); // println is not required for the exam
// Second read
localX = X;
System.out.println(localX); // println is not required for the exam
lockForVariableY.readLock().lock();
var localY = Y;
lockForVariableX.readLock().unlock();
});
t1.start(); t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String args[]) throws InterruptedException {
TwoPL ex = new TwoPL();
ex.ex1();
ex.ex2();
}
}
Week 1: Exam Preparatory Exercise
Any Java program might have the following possible outcomes: (i) runs and provides normal output, (ii) fails at compile time, (iii) a non-caught exception is thrown, or (iv) deadlock or livelock. Describe the outcome of both compiling GuestBook and, when possible, running the resulting bytecode.
import java.util.*;
public class GuestBook {
private List<String> concatenation;
public GuestBook() {
concatenation = new ArrayList<>(2);
}
public void signBook(String user) {
concatenation.add("Greetings from " + user+" !");
}
public static void main(String[] args) {
var book = new GuestBook();
String localStars = "Rowan Atkinson; Eric Burdon";
Thread t[] = new Thread[2];
int i = 0;
for (var star : localStars.split(";"))
t[i++] = new Thread(() -> book.signBook(star));
for (var thread : t) thread.join();
System.out.println(String.join(" and ", book.concatenation));
}
}
What is the issue with the SportSupport program? Choose one of the issues listed in the outcomes list.A
A.Fails at compile time
B.Non-caught exception is thrown
C.Deadlock or Livelock
D.Runs and provides normal output