Java - 死锁使用SWAP函数解决互斥
Java - Deadlock using SWAP function to solve mutual exclusion
我想用Swap函数解决互斥问题,但是程序死锁了,不知道为什么。好像是一个线程连续执行两次才会出现这个问题。
交换锁逻辑:
每个线程都使用一个 local 变量和一个 shared 变量。
线程首先锁定其 local 变量(例如假设 1 值)。
当线程 local 变量被解锁(例如假设 0 值)它可以执行临界区,如果线程 local 变量被锁定(例如假设1值)线程处于busy-waiting(忙等待测试局部变量解锁并调用swap函数)
交换函数将 local 变量设置为 shared 变量值并且 viceversa.The 交换函数必须是原子的。
当线程调用交换时,如果 "shared" 变量在交换后为 0(解锁),则 shared 变量为 1 且 local 到 0。
所以只有那个线程可以访问临界区,其他线程不能访问。
最后(不再有临界区)线程解锁 shared 变量。
主要
public class Mutex {
public static void main(String []args){
LockVar var = new LockVar(0);
ThreadSwap th0 = new ThreadSwap(var);
ThreadSwap th1 = new ThreadSwap(var);
ThreadSwap th2 = new ThreadSwap(var);
th0.start();
th1.start();
th2.start();
}
}
线程Class
(重点强调这类互斥量的逻辑)
class ThreadSwap extends Thread{
private LockVar shared_var;
public ThreadSwap(LockVar var){
this.shared_var = var;
}
@Override
public void run(){
LockVar local = new LockVar(1);
while(true){
---> local.setVar(1);
---> while(local.getVar() == 1){Synch.SWAP(shared_var, local);}
System.out.println("Thread " + getId() + " exec critical section.");
// Critical section
System.out.println("Thread " + getId() + " is leaving critical section.");
---> shared_var.setVar(0);
}
}
}
交换功能
class Synch{
public static synchronized void SWAP(LockVar shared, LockVar local){
int temp = shared.getVar();
shared.setVar(local.getVar());
local.setVar(temp);
}
...
}
共享变量Class
class LockVar{
private volatile int var;
public LockVar(int value){
this.var = value;
}
public int getVar(){
return this.var;
}
public void setVar(int value){
this.var=value;
}
}
想象一下这个场景:
- 第一个线程交换本地和 shared_var。现在 shared_var 是 1 而本地是 0.
- 由于 SWAP 上的同步是在 Synch class 上进行的,一旦第一个线程完成 SWAP,线程 2 就可以进入它。线程 2 使 temp = 1,此时监视器切换回线程 1。
- 线程 1 完成循环的第一次迭代,打印 exec 的消息并离开临界区并设置 shared_var = 0。监视器移至线程 2。
- 线程 2 继续执行 SWAP。它离开的地方。它执行
shared.setVar(local.getVar());
(现在 shared_var == 1)和 local.setVar(temp);
(记住步骤 2 中的温度为 1)。
死锁已经产生:shared_var为1,临界区内没有线程。这是因为 SWAP 不是原子的(监视器可以远离执行同步方法的线程,它只是不允许其他线程进入这种方法,也不允许其他方法在同一个锁上同步(class 在这种情况下静态方法的实例,在非静态方法的情况下是对象的实例))。
为了解决这个问题,您不应该允许 shared 在 SWAP 执行时更改,方法是找到一种使其成为原子的方法。一种可能性是摆脱 local 并使用 compareAndSet on an AtomicBoolean ,它现在将扮演 shared_var 的角色。
原子类型保证原子性和易变性(参见documentation)。这样,每个线程都应该获得对用于发信号的 AtomicBoolean 的引用(请原谅我松散的命名法),并使用 compareAndSet 以其他线程立即可见的方式自动更新变量的值:
import java.util.concurrent.atomic.AtomicBoolean;
public class Mutex {
public static void main(String []args){
AtomicBoolean isLocked = new AtomicBoolean(false);
ThreadSwap th0 = new ThreadSwap(isLocked);
ThreadSwap th1 = new ThreadSwap(isLocked);
ThreadSwap th2 = new ThreadSwap(isLocked);
th0.start();
th1.start();
th2.start();
}
}
class ThreadSwap extends Thread {
private AtomicBoolean shared_IsLocked;
public ThreadSwap(AtomicBoolean var){
this.shared_IsLocked = var;
}
@Override
public void run(){
while(true){
// While the flag is true (locked), keep checking
// If it is false (not locked), atomically change its value and keep going
while(!shared_IsLocked.compareAndSet(false, true));
System.out.println("Thread " + getId() + " exec critical section.");
// Critical section
System.out.println("Thread " + getId() + " is leaving critical section.");
shared_IsLocked.set(false);
}
}
}
我想用Swap函数解决互斥问题,但是程序死锁了,不知道为什么。好像是一个线程连续执行两次才会出现这个问题。
交换锁逻辑:
每个线程都使用一个 local 变量和一个 shared 变量。 线程首先锁定其 local 变量(例如假设 1 值)。 当线程 local 变量被解锁(例如假设 0 值)它可以执行临界区,如果线程 local 变量被锁定(例如假设1值)线程处于busy-waiting(忙等待测试局部变量解锁并调用swap函数)
交换函数将 local 变量设置为 shared 变量值并且 viceversa.The 交换函数必须是原子的。
当线程调用交换时,如果 "shared" 变量在交换后为 0(解锁),则 shared 变量为 1 且 local 到 0。 所以只有那个线程可以访问临界区,其他线程不能访问。
最后(不再有临界区)线程解锁 shared 变量。
主要
public class Mutex {
public static void main(String []args){
LockVar var = new LockVar(0);
ThreadSwap th0 = new ThreadSwap(var);
ThreadSwap th1 = new ThreadSwap(var);
ThreadSwap th2 = new ThreadSwap(var);
th0.start();
th1.start();
th2.start();
}
}
线程Class (重点强调这类互斥量的逻辑)
class ThreadSwap extends Thread{
private LockVar shared_var;
public ThreadSwap(LockVar var){
this.shared_var = var;
}
@Override
public void run(){
LockVar local = new LockVar(1);
while(true){
---> local.setVar(1);
---> while(local.getVar() == 1){Synch.SWAP(shared_var, local);}
System.out.println("Thread " + getId() + " exec critical section.");
// Critical section
System.out.println("Thread " + getId() + " is leaving critical section.");
---> shared_var.setVar(0);
}
}
}
交换功能
class Synch{
public static synchronized void SWAP(LockVar shared, LockVar local){
int temp = shared.getVar();
shared.setVar(local.getVar());
local.setVar(temp);
}
...
}
共享变量Class
class LockVar{
private volatile int var;
public LockVar(int value){
this.var = value;
}
public int getVar(){
return this.var;
}
public void setVar(int value){
this.var=value;
}
}
想象一下这个场景:
- 第一个线程交换本地和 shared_var。现在 shared_var 是 1 而本地是 0.
- 由于 SWAP 上的同步是在 Synch class 上进行的,一旦第一个线程完成 SWAP,线程 2 就可以进入它。线程 2 使 temp = 1,此时监视器切换回线程 1。
- 线程 1 完成循环的第一次迭代,打印 exec 的消息并离开临界区并设置 shared_var = 0。监视器移至线程 2。
- 线程 2 继续执行 SWAP。它离开的地方。它执行
shared.setVar(local.getVar());
(现在 shared_var == 1)和local.setVar(temp);
(记住步骤 2 中的温度为 1)。
死锁已经产生:shared_var为1,临界区内没有线程。这是因为 SWAP 不是原子的(监视器可以远离执行同步方法的线程,它只是不允许其他线程进入这种方法,也不允许其他方法在同一个锁上同步(class 在这种情况下静态方法的实例,在非静态方法的情况下是对象的实例))。
为了解决这个问题,您不应该允许 shared 在 SWAP 执行时更改,方法是找到一种使其成为原子的方法。一种可能性是摆脱 local 并使用 compareAndSet on an AtomicBoolean ,它现在将扮演 shared_var 的角色。
原子类型保证原子性和易变性(参见documentation)。这样,每个线程都应该获得对用于发信号的 AtomicBoolean 的引用(请原谅我松散的命名法),并使用 compareAndSet 以其他线程立即可见的方式自动更新变量的值:
import java.util.concurrent.atomic.AtomicBoolean;
public class Mutex {
public static void main(String []args){
AtomicBoolean isLocked = new AtomicBoolean(false);
ThreadSwap th0 = new ThreadSwap(isLocked);
ThreadSwap th1 = new ThreadSwap(isLocked);
ThreadSwap th2 = new ThreadSwap(isLocked);
th0.start();
th1.start();
th2.start();
}
}
class ThreadSwap extends Thread {
private AtomicBoolean shared_IsLocked;
public ThreadSwap(AtomicBoolean var){
this.shared_IsLocked = var;
}
@Override
public void run(){
while(true){
// While the flag is true (locked), keep checking
// If it is false (not locked), atomically change its value and keep going
while(!shared_IsLocked.compareAndSet(false, true));
System.out.println("Thread " + getId() + " exec critical section.");
// Critical section
System.out.println("Thread " + getId() + " is leaving critical section.");
shared_IsLocked.set(false);
}
}
}