/* * Class SemaforoEV * * This software is developed for Choral devices with Java. * Copyright Choral srl. All Rights reserved. */ package general; import java.util.*; /** * Advanced semaphore, with timeout * * @version 1.00 <BR> <i>Last update</i>: 06-07-2007 * @author alessioza * */ public class SemaforoEV { /* * variables */ /** Semaphore value (with available tokens) */ protected int value; /** Number of waiting threads */ protected int waitNum = 0; /** Max number of available tokens (default=1, binary semaphore = MUTUAL EXCLUSION) */ protected int maxvalue = 1; /** FIFO list for waiting queue * Set queue capacity, default = 10 */ protected Vector codaAttesa = new Vector(); /** true = FIFO management, false = LIFO management */ protected boolean isFifo = true; /** Owner of the semaphore, if private */ protected Thread tit = null; /* Special values * * Please note: to assign a numeric value of type Long, you need to add * an 'L' character at the end */ /** Immediate synchronization, immediately executes or skips the execution */ public static final long IMMEDIATE = 1L; /** Wait without timeout */ public static final long NOTIMEOUT = 0L; /** Timeout expired */ public static final long EXPIRED = 0L; /** Timeout not expired */ public static final long INTIME = 1L; /* * constructors */ public SemaforoEV(int v, int max, boolean fifo) { value = v; maxvalue = max; isFifo = fifo; } public SemaforoEV(int v, int max) { this(v,max,true); } public SemaforoEV(int v) { this(v,v); } public SemaforoEV(boolean b) { // binary semaphore this(b?1:0,1); } public SemaforoEV() { // private semaphore this(false); tit = Thread.currentThread(); /* the owner is the current thread */ } /* * methods */ public synchronized void getCoin() { // REQUEST "TOKEN" Thread curTh = Thread.currentThread(); if (tit != null && tit != curTh) { // control on the owner throw new InvalidThreadException(); } if (value == 0) { /* If NO tokens available, stop thread execution and add to queue */ waitNum++; if(isFifo) { // add to FIFO queue codaAttesa.addElement(new WaitingThread(curTh, false)); } else { // add to LIFO head (position 0) codaAttesa.insertElementAt(new WaitingThread(curTh, false), 0); } //isFifo //System.out.println("GET: Put "+curTh.getName()+" in the queue"); //System.out.println("GET: Number of thread in the queue: "+waitNum); while(true) { try { wait(); /* wait() call freeze method (and thread) execution in * this point until notifyAll() */ } catch (InterruptedException ie) { } //catch /* if you have to wake up this thread, it is usually the first, * but in the case of LIFO queue, another thread can be placed * in head and be suspended, so you have to look linearly */ for (int i=0; i<codaAttesa.size(); i++) { // check all threads of the queue WaitingThread wt = (WaitingThread)codaAttesa.elementAt(i); if (wt.th == curTh) { // if found current thread... if (wt.wakenUp) { // and it WAS AWAKENED... //System.out.println("GET: "+curTh.getName()+" was awakened, remove it from queue"); codaAttesa.removeElementAt(i); waitNum--; // then semaphore value is already OK return; } else break; // otherwise, if it is NOT already awakened, is re-suspend */ } //if wt.th else; } //for } //while } else { value--; //System.out.println("GET: I can execute thread "+curTh.getName()+" immediately"); } //if value /* if there are tokens available, then the thread can continue * execution and simply decrements the semaphore */ //System.out.println("GET: semaphore values is now: "+value); //System.out.println("GET: number of thread in the queue: "+waitNum); } //getCoin public synchronized long getCoin(long timeout) { // REQUEST "TOKENS" with timeout if (timeout == NOTIMEOUT) { getCoin(); // bring back to normal getCoin return INTIME; } Thread curTh = Thread.currentThread(); if (tit != null && tit != curTh) { throw new InvalidThreadException(); } if (value == 0) { /* if NOT tokens available, stop thread execution and add to queue */ if (timeout == IMMEDIATE) return EXPIRED; // immediate synchronization NOT possible // otherwise wait in queue long exp = System.currentTimeMillis() + timeout; // expiration moment waitNum++; if(isFifo) { // add to FIFO queue codaAttesa.addElement(new WaitingThread(curTh, false)); } else { // add to LIFO head (position 0) codaAttesa.insertElementAt(new WaitingThread(curTh, false), 0); } //System.out.println("GET: Put "+curTh.getName()+" in the queue"); //System.out.println("GET: Number of threads in the queue: "+waitNum); long diffTime = timeout; // actual time to wait while(true) { if (diffTime>0) { try { // wakes up the thread when the timeout expires wait(diffTime); } catch (InterruptedException ie) { } //catch } //if diffTime = exp - System.currentTimeMillis(); /* if you have to wake up this thread, it is usually the first, * but in the case of LIFO queue, another thread can be placed * in head and be suspended, so you have to look linearly */ for (int i=0; i<codaAttesa.size(); i++) { WaitingThread wt = (WaitingThread)codaAttesa.elementAt(i); if (wt.th == curTh) { // if found current thread... if (wt.wakenUp) { // and it WAS AWAKENED... //System.out.println("GET: "+curTh.getName()+" was awakened, remove it from queue"); codaAttesa.removeElementAt(i); waitNum--; // then semaphore value is already OK return diffTime > 0L ? diffTime : INTIME; // however >0 } else if (diffTime <=0) { // wake up for timeout codaAttesa.removeElementAt(i); waitNum--; /* semaphore vaue is already OK */ return EXPIRED; // timeout expired } else break; // otherwise, if it is NOT already awakened, is re-suspend */ } //if wt.th else; } //for } //while } else { value--; /* decrease semaphore */ //System.out.println("GET: I can execute thread "+curTh.getName()+" immediately"); } //if value //System.out.println("GET: Semaphore value is now: "+value); //System.out.println("GET: Number of threads in the queue is: "+waitNum); return timeout; // not suspensive } //getCoin(long timeout) public synchronized void putCoin() { // PUT "TOKEN" if (value == maxvalue) return; if (waitNum > 0) { // if there are thread in the queue, try to satisfy them immediately //System.out.println("PUT: there are threads in the queue"); for (int i=0; i<codaAttesa.size(); i++) { // linear search in the list WaitingThread wt = (WaitingThread)codaAttesa.elementAt(i); if (!wt.wakenUp) { // if thread not already awakened, then I can awaken //System.out.println("PUT: Prepare thread for awaken "+wt.th.getName()); wt.wakenUp = true; // waitNum--; NO, decrease of waitNumis already performed into GET break; // exit for loop } } //for //System.out.println("Notify to all threads"); notifyAll(); } else { // No threads in the queue, increase only semaphore value value++; //System.out.println("PUT: no threads in the queue, increase only semaphore value"); } //waitNum //System.out.println("PUT: semaphore value is now: "+value); //System.out.println("PUT: Number of threads in the queue: "+waitNum); } //putCoin public synchronized Thread waitingThread(int pos) { /* Waiting thread with 'pos' index in the queue */ if (pos >= codaAttesa.size()) return null; return ((WaitingThread)codaAttesa.elementAt(pos)).th; } public synchronized int getValue() { /* return number of available tokens */ return value; } public synchronized int getQueued() { /* return number of threads in the queue */ return waitNum; } public synchronized int getCapacity() { /* return queue capacity */ return codaAttesa.capacity(); } public synchronized String possDa() { /* return semaphore owner */ return tit == null ? "nessuno" : tit.getName(); } /* * Internal class * Waiting thread descriptor */ protected class WaitingThread { /* * variables */ Thread th; // Thread ID boolean wakenUp; // awakened? int qty; // request quantity int prio; /* waiting priority * low values = high priority */ static final int MIN_PRIO = 10; static final int MAX_PRIO = 1; /* * constructors */ WaitingThread(Thread t, boolean w, int q, int p) { th = t; wakenUp = w; qty = q; prio = p; } WaitingThread(Thread t, boolean w, int q) { this(t,w,q,MIN_PRIO); } WaitingThread(Thread t, boolean w) { this(t,w,1,MIN_PRIO); } } //WaitingThread } //SemaforoEV