1

I would like to solve mutual exclusion using the Swap function but the program suffer from deadlock and I don't know why. It seems the problem occur when a thread exec two consecutive times.

The swap lock logic:

Every thread make use of a local variable and a shared variable. A thread at first lock its local variable (e.g. assume 1 value). When a thread local variable is unlocked (e.g. assume 0 value) it can execute the critical section, if the thread local variable is locked (e.g. assume 1 value) the thread is in a busy-waiting (the busy waiting tests the local variable unlocking and calls the swap function)

The swap function sets the local variable to the shared variable value and viceversa.The swap function has to be ATOMIC.

When a thread call swap, if the the "shared" variables is 0 (unlock) after swap we have that shared variable is 1 and the local to 0. So only that thread can access to the critical section no others.

At the end (no more critical section) the thread unlock the shared variable.

Main

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();
    }
}

Thread Class (The logic of this type of mutex is emphasized)

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);
        }
    }
}

Swap function

class Synch{
public static synchronized void SWAP(LockVar shared, LockVar local){
    int temp = shared.getVar();
    shared.setVar(local.getVar());
    local.setVar(temp);
}
...
}

Shared var 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;
    }
}
Wojciech Wirzbicki
  • 3,887
  • 6
  • 36
  • 59
  • What is the expected outcome? What is the actual outcome you get? Note you are using setVar at the end of each loop in a non-synchronized manner. – user2891462 Apr 08 '15 at 13:29
  • Sorry i'll edit the right code.. – MadDogTannen Apr 08 '15 at 13:48
  • The expeted outcome is a continuous threads executions, if a thread is in the critical section no other threads can execute their critical section. The actual outcome is a deadlock, the code works for 3 - 4 thread execution and than a deadlock occurs. (The shared varables doesn't assumes 0 value) – MadDogTannen Apr 08 '15 at 14:02
  • Yes, infact after debug I noticed that after the `setVar(0)` call the value of "var" attribute of shared_var object didn't change. – MadDogTannen Apr 08 '15 at 14:11
  • My bet is that the variable is being set to 0 at the end of the loop but quickly overwritten by another thread which is in the middle of SWAP. My current environment is not set for Java development at the moment, I'll give it a go tonight if it is still unresolved :) – user2891462 Apr 08 '15 at 14:24
  • It makes sense, thanks for the hint, I'll think about it. – MadDogTannen Apr 08 '15 at 14:53
  • Mmhh, it seems, because SWAP is atomic, it couldn't be interrupted – MadDogTannen Apr 08 '15 at 14:56
  • Added an answer explaining the problem your code had and how to fix it by using an atomic operation (your SWAP is not atomic). – user2891462 Apr 08 '15 at 16:25

1 Answers1

0

Imagine this scenario:

  1. The first thread swaps local and shared_var. Now shared_var is 1 and local is 0.
  2. Since the synchronization on SWAP is on the Synch class, as soon as the first thread is done with SWAP, Thread 2 can get into it. Thread 2 makes temp = 1, and at that point the monitor switches back to Thread 1.
  3. Thread 1 finishes the first iteration of the loop, printing the messages of exec and leaving critical section and setting shared_var = 0. Monitor moves to Thread 2.
  4. Thread 2 proceeds with SWAP. where it left it. It executes shared.setVar(local.getVar()); (now shared_var == 1) and local.setVar(temp); (remember temp is 1 from step 2).

The deadlock has been produced: shared_var is 1 and no thread is in the critical section. This is because SWAP is not atomic (the monitor can move away from a thread executing a synchronized method, it will just not allow other threads to enter such method nor others method synchronized on the same lock (the class in the case of a static method, the instance of the object in the case of a non-static method)).

In order to fix this you should not allow shared to change while SWAP is executing, by finding a way of making it atomic. A possibility would be to get rid of local and use compareAndSet on an AtomicBoolean which would play the role of shared_var at the moment.

Atomic types guarantee atomicity and volatility (see documentation). This way, every thread should get a reference (excuse my loose nomenclature) to the AtomicBoolean used for signaling and use compareAndSet to atomically update the value of the variable in a way that is visible immediately to the other threads:

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);
    }
  }
}
user2891462
  • 3,033
  • 2
  • 32
  • 60
  • Thanks a lot, you help me to improve my knowledge about monitor. So this is a solution: **Thread Class** ... ... ... Synch.SET(shared_var, 0); ... **Synch Class** ` class Synch{ public synchronized static void SET(LockVar shared, int value){ shared.setVar(value); } public synchronized static void SWAP(LockVar shared, LockVar local){ int temp = shared.getVar(); shared.setVar(local.getVar()); local.setVar(temp); } ` – MadDogTannen Apr 08 '15 at 17:42