1

I am trying to do a leader election problem with variable speed algorithm. I let one thread to be the master thread and multiple other threads to compete to be the leader. The thread with the largest id will become the leader, and the unique ids read from a input.dat are assigned to the threads. Each thread can only talk to its neighbors, it passes its id to its left or right neighbors, the neighbor will compare the received id and its own id and keep the larger one and forward it to the next neighbor. Finally, when one thread receives an id equal to its own id, that is must be the leader, then we can terminate the process.

In one round of the algorithm, each thread will have to wait for 2^(u - 1) rounds to pass its max_id_seen_so_far to its next direct neighbor according to the variable speed algorithm, where u is the max id the thread has seen so far. The master thread will start the xth round if all threads finished the (x - 1)th round. I use a counter as the flag, in each round, each thread will reduce the counter by one and wait. When the counter is 0, the master thread will be awaken and reset the counter to the number of the threads and signal all the threads for the new round.


class Ids {

    private int[] ids;
    private int number;
    private boolean terminate;
    private int count;

    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public boolean isTerminate() {
        return terminate;
    }
    public void setTerminate(boolean terminate) {
        this.terminate = terminate;
    }
    public int[] getIds() {
        return ids;
    }
    public void setIds(int[] ids) {
        this.ids = ids;
    }
    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }

    public int getOneId(int index) {
        return this.ids[index];
    }

    public void setOneId(int index, int id) {
        this.ids[index] = id;
    }
    @Override
    public String toString() {
        return "Ids [ids=" + Arrays.toString(ids) + ", number=" + number + "]";
    }
}

class Process {

    private Ids ids;
    private int own_id;
    private int max_id;
    private int count;
    private int index;
    private int delay;

    private Lock lock = new ReentrantLock();
    private Condition masterCondition = lock.newCondition();
    private Condition slaveryCondition = lock.newCondition();

    public Process(Ids ids) {
        super();
        this.ids = ids;
    }

    public Process(Ids ids, int own_id, int index) {
        super();
        this.ids = ids;
        this.own_id = own_id;
        this.index = index;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public void runMaster() {
        try {
            while(true) {
                lock.lock();
                while(ids.getCount() != 0) {
                    masterCondition.await();
                }
                // work
                ids.setCount(ids.getNumber());
                slaveryCondition.signalAll();
                if(ids.isTerminate()) {
                    return;
                }
                lock.unlock();
            }

        } catch (Exception e) {

        }finally {

        }
    }

    public void runSlavery() {
        int size = ids.getNumber();
        // get new id;
        max_id = own_id;
        delay = 0;

        while(true) {

            // wait for the start of the round, until the leader is found
            int new_id = ids.getIds()[(index - 1) < 0 ? (size - 1) : (index - 1)];

            if (new_id == own_id) {
                ids.setTerminate(true);
                break;
            }

            if(new_id > max_id) {
                max_id = new_id;
                delay = (int) Math.pow(2, new_id - 1);
            }else {
                // discard the new id;
                if (delay == 0) {
                    // pass the max_id to the right neighbor
                    ids.setOneId(index, max_id);
                    delay = (int) Math.pow(2, max_id - 1);
                }

                delay--;
            }

            if (ids.isTerminate()) {
                break;
            }

            try {
                lock.lock();
                ids.setCount(ids.getCount() - 1);
                while(ids.getCount() > 0) {
                    slaveryCondition.await();
//                  Thread.sleep(1000);
                    System.out.println(ids.getCount());
                }
                // one round is over
                masterCondition.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

public class Variable_speed {

    public static void main(String[] args) throws InterruptedException {
        // Create a resource class
        Ids ids = new Ids();

        Scanner scanner;
        try {
            scanner = new Scanner(new File("data//input.dat"));
            int n = scanner.nextInt();
            int[] arr_id = new int[n];
            for(int i = 0; i < n; i++) {
                arr_id[i]= scanner.nextInt(); 
            }

            ids.setIds(arr_id);
            ids.setNumber(n);
            ids.setCount(n);

            // Create a master thread
            Process master = new Process(ids, -1, -1);
            new Thread(() -> master.runMaster(), "master").start();
            // create slavery threads
            for(int i = 0; i < n; i++) {
                Process process = new Process(ids, arr_id[i], i);
                new Thread(() -> process.runSlavery(), "slavery").start();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

}

However, my concurrency program fails to awake the master thread when all the threads finish their first round, the program is stuck at the masterCondition.await(). I am not good at Java concurrency, please tell me where my problem is, I appreciate that.

Qiang Yao
  • 165
  • 12
  • Please share your thread code, thanks – jr593 Sep 11 '19 at 15:05
  • @jr593 The thread codes are inside the Process class, the master thread code is in the runMaster() and slavery thread code is in the runSlavery(). I used 1. masterCondition.await(); slaveryCondition.signalAll(). 2. slaveryCondition.await(), masterCondition.signal(). – Qiang Yao Sep 11 '19 at 15:15
  • @Erik Yes, I read through that post, I think we meet the same problem. I think my problem is that to awake the master thread, the ids.getCount() has to be less or equal to 0. But since the threads ids.getCount() and ids.setCount(ids.getCount() - 1) are not mutually exclusive, it is very hard for the count to be 0. I just don't know how to solve it. I used lock.lock() before the read-write operation, it seems I have a problem with the concurrency. – Qiang Yao Sep 11 '19 at 15:44
  • Create a new question with this new findings – Erik Sep 12 '19 at 09:31
  • @Erik Sorry, I haven't checked the comments for a long time. I don't quite follow what you mean by creating a new question. But I have solved that problem before. I just used the strategy of semaphore barrier to stop the threads before starting a new round and uses a mutex to keep the mutual exclusive. – Qiang Yao Sep 19 '19 at 20:05

0 Answers0