1

My program require to print backward from 10 to 1. Each number print from one thread. It uses one lock with multiple condition objects. But the program cause a dead lock when I run it. This is my program.


This class working fine

import java.util.concurrent.*;
import java.util.*;

public class Backward {
   public static void main(String[] args) {
      BackwardThread[] threads = new BackwardThread[10];
      MonitorArray monitorArray = new MonitorArray(10);
      for(int i = 0; i < 10; ++i) {
         threads[i] = new BackwardThread("thread" + i, i, monitorArray);
         threads[i].start();
      }
   }
}

This class is working fine

import java.util.concurrent.*;
import java.util.*;

public class BackwardThread extends Thread {
   private int id;
   private MonitorArray monitorArray;

   public BackwardThread(String name, int id, MonitorArray monitorArray) {
       super(name);
       this.id = id;
       this.monitorArray = monitorArray;
   }

  public void run() {
      monitorArray.waitTurn(id);
      System.out.println("hello world thread id = " + id);
      monitorArray.signalDone(id);
  }
}

It seem all thread is lock forever on and conditions[id].signal() doesn't work.

import java.util.concurrent.locks.*;
import java.util.concurrent.locks.Condition;

public class MonitorArray {

    private Lock lockvar;
    private Condition[] conditions;
    private int turn;

    public MonitorArray(int num) {
        this.lockvar = new ReentrantLock();
        this.conditions = new Condition[num];
        turn = num;
        for (int i = 0; i < num; ++i) {
            conditions[i] = lockvar.newCondition();
        }
        // TODO: need to initialize new variable here
    }
    public void waitTurn(int id) {
        lockvar.lock();
        while (id != turn) {
            try {
                conditions[id].await();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
        lockvar.unlock();
    }

    public void signalDone(int id) {
        lockvar.lock();
        // TODO: Need to modify new variable here to allow one of the threads
        // blocked on the while to continue
        turn--;
        if (id != 0) {
            conditions[id].signal();
        }

        lockvar.unlock();
    }
}
vtc
  • 66
  • 5
  • Are you getting errors or all your threads are in waiting ? I suppose since the id[0-9] and turn(10) are never matching, latter is happening. – happyHelper Oct 07 '17 at 12:09
  • Thank you, happyHelper! All of my threads are in waiting. But I think I reduce "turn" in signalDone() so It should match the condition and release the threads one by one. – vtc Oct 07 '17 at 12:20
  • Seemed like an interesting problem so I tried running it with minor tweaks, but similar thing is happening for me as well. The threads are not released. Instead of signal if I use `signalAll()`, it works though. The signal is waking up a thread that does not match the firstwaiter thread id I guess. – happyHelper Oct 07 '17 at 13:25

1 Answers1

0

I have found the solution for this, I will give my explanation in the comment of my code

import java.util.concurrent.locks.*;
import java.util.concurrent.locks.Condition;

public class MonitorArray {

    private Lock lockvar;
    private Condition[] conditions;
    private int turn;

    public MonitorArray(int num) {
        this.lockvar = new ReentrantLock();
        this.conditions = new Condition[num];

        /*
        / the turn value should should be num-1(9) instead of num(10) 
        / because if turn = 10 so all threads will be in waiting section,
        / so there will be no thread to send the signal to wake up other threads
        */
        turn = num-1;
        for (int i = 0; i < num; ++i) {
            conditions[i] = lockvar.newCondition();
        }

    }
    public void waitTurn(int id) {
        lockvar.lock();
        while (id != turn) {
            try {
                conditions[id].await();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
        lockvar.unlock();
    }

    public void signalDone(int id) {
        lockvar.lock();
        // TODO: Need to modify new variable here to allow one of the threads
        // blocked on the while to continue
        turn--;
        if (id != 0) {

        /* 
        / this should be conditions[turn].signal(), not conditions[id] 
        / because a thread cannot wake up themself,
        / when we use condition[turn] we are in thread 9 and we sent signal to wake up thread 8, 
        / and furthermore, turn is reduced value and wake up the next smaller thread.
        */
            conditions[turn].signal();
        }

        lockvar.unlock();
    }
}
vtc
  • 66
  • 5