001/*
002 * $Id$
003 */
004
005package edu.jas.util;
006
007
008import java.util.concurrent.Semaphore;
009
010import org.apache.logging.log4j.Logger;
011import org.apache.logging.log4j.LogManager; 
012
013
014//import edu.unima.ky.parallel.Semaphore;
015
016/**
017 * Terminating helper class. Like a barrier, but with coming and going.
018 * @author Heinz Kredel
019 */
020
021public class Terminator {
022
023
024    private static final Logger logger = LogManager.getLogger(Terminator.class);
025
026
027    private final int workers;
028
029
030    private int idler;
031
032
033    private final Semaphore fin;
034
035
036    private boolean done; // volatile not required since synchronized  
037
038
039    /**
040     * Terminator.
041     * @param workers number of expected threads.
042     */
043    public Terminator(int workers) {
044        this.workers = workers;
045        fin = new Semaphore(0);
046        done = false;
047        idler = 0;
048        logger.info("constructor, workers = {}", workers);
049    }
050
051
052    /**
053     * to string
054     */
055    @Override
056    public String toString() {
057        return "Terminator(" + done + ",workers=" + workers + ",idler=" + idler + ")";
058    }
059
060
061    /**
062     * beIdle.
063     * Checks for release().
064     */
065    public synchronized void beIdle() {
066        idler++;
067        logger.info("beIdle, idler = {}", idler);
068        if (idler >= workers) {
069            done = true;
070            fin.release(); //fin.V();
071        }
072    }
073
074
075    /**
076     * initIdle.
077     * No check for release().
078     * @param i number of idle threads.
079     */
080    public synchronized void initIdle(int i) {
081        idler += i;
082        logger.info("initIdle, idler = {}", idler);
083        if ( idler > workers ) {
084            if (done) {
085                idler = workers;
086            } else {
087                throw new RuntimeException("idler > workers: " + idler + " > " + workers);
088            }
089        }
090    }
091
092
093    /**
094     * beIdle.
095     * Checks for release().
096     * @param i number of idle threads.
097     */
098    public synchronized void beIdle(int i) {
099        idler += i;
100        logger.info("beIdle, idler = {}", idler);
101        if (idler >= workers) {
102            done = true;
103            fin.release(); //fin.V();
104        }
105    }
106
107
108    /**
109     * allIdle.
110     * Checks for release().
111     */
112    public synchronized void allIdle() {
113        idler = workers;
114        logger.info("allIdle");
115        done = true;
116        fin.release(); //fin.V();
117    }
118
119
120    /**
121     * notIdle.
122     */
123    public synchronized void notIdle() {
124        idler--;
125        logger.info("notIdle, idler = {}", idler);
126        if ( idler < 0 ) {
127            throw new RuntimeException("idler < 0");
128        }
129    }
130
131
132    /**
133     * getJobs.
134     * @return number of possible jobs.
135     */
136    public synchronized int getJobs() {
137        return (workers - idler);
138    }
139
140
141    /**
142     * hasJobs.
143     * @return true, if there are possibly jobs, else false.
144     */
145    public synchronized boolean hasJobs() {
146        return (idler < workers);
147    }
148
149
150    /**
151     * Release if possible.
152     */
153    public synchronized void release() {
154        logger.info("release = {}", this);
155        if ( idler >= workers ) {
156            done = true;
157            fin.release(); 
158        }
159        //logger.info("release, idler = {}", idler);
160    }
161
162
163    /**
164     * Wait until released.
165     */
166    public void waitDone() {
167        try {
168            fin.acquire(); 
169        } catch (InterruptedException e) {
170            Thread.currentThread().interrupt();
171        }
172        logger.info("waitDone {}", this);
173    }
174
175}