diff options
author | eea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1999-08-24 23:10:15 +0000 |
---|---|---|
committer | eea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1999-08-24 23:10:15 +0000 |
commit | e4012b2dc8297540c9501a10daa8b8746d55297e (patch) | |
tree | ef60f5324a9022443eb683594e2d415ea46d08eb | |
parent | f69420de3b964a4f1de9b9c310ca9ced2461e24e (diff) | |
download | ATCD-e4012b2dc8297540c9501a10daa8b8746d55297e.tar.gz |
Updated source files for Concurrency.
-rw-r--r-- | java/JACE/Concurrency/AbstractLock.java | 269 | ||||
-rw-r--r-- | java/JACE/Concurrency/Condition.java | 124 | ||||
-rw-r--r-- | java/JACE/Concurrency/LockAdapter.java | 262 | ||||
-rw-r--r-- | java/JACE/Concurrency/LockException.java | 28 | ||||
-rw-r--r-- | java/JACE/Concurrency/Mutex.java | 239 | ||||
-rw-r--r-- | java/JACE/Concurrency/RWMutex.java | 268 | ||||
-rw-r--r-- | java/JACE/Concurrency/RenewObject.java | 36 | ||||
-rw-r--r-- | java/JACE/Concurrency/Semaphore.java | 263 | ||||
-rw-r--r-- | java/JACE/Concurrency/ThreadManager.java | 113 | ||||
-rw-r--r-- | java/JACE/Concurrency/Token.java | 301 | ||||
-rw-r--r-- | java/JACE/Concurrency/WaitObject.java | 39 | ||||
-rw-r--r-- | java/JACE/Concurrency/package.html | 15 |
12 files changed, 1957 insertions, 0 deletions
diff --git a/java/JACE/Concurrency/AbstractLock.java b/java/JACE/Concurrency/AbstractLock.java new file mode 100644 index 00000000000..c8afaf789ae --- /dev/null +++ b/java/JACE/Concurrency/AbstractLock.java @@ -0,0 +1,269 @@ +/************************************************* + * + * = PACKAGE + * JACE.Concurrency + * + * = FILENAME + * Lock.java + * + *@author Everett Anderson + * + *************************************************/ +package JACE.Concurrency; + +import JACE.ASX.*; + +/** + * Interface for any Java ACE synchronization mechanism. + * <P> + * Defines the interface for Token, Mutex, RWMutex, Semaphore, + * and the RemoteLock proxies in the Token service, as well as + * the possible constant return values. + * <P> + * Methods which take TimeValue timeouts can throw + * JACE.ASX.TimeoutExceptions. The locks should continue to + * function properly after a thread times out or is interrupted. + * <em>Also note that the timeouts are absolute time-of-day + * values, not relative times.</em> + * <P> + * An AbstractLock.FAILURE can be returned for an undefined type of + * failure. + * <P> + * You can assume that + * AbstractLock.FAILURE < AbstractLock.SUCCESS < AbstractLock.SLEEPHOOK + * <P> + * Any method can throw a LockException, providing a way to return + * unusual error cases in future types of locks (such as the Token + * service). + * <P> + * It is safe to call release () in a finally block, since it will + * return FAILURE if the accessing thread is not the owner. + * + */ +public interface AbstractLock +{ + /** + * Generic failure indication, used as a return value. + */ + public static final int FAILURE = -1; + + /** + * Success indication, used as a return value. + */ + int SUCCESS = 0; + + /** + * Success indication, but notes that the thread had to sleep + * to complete it (and it called the sleep hook). Used as a + * return value. + */ + int SLEEPHOOK = 1; + + + /** + * Acquire ownership of the lock, blocking indefinitely if necessary. + * <P> + *@return AbstractLock.FAILURE or AbstractLock.SUCCESS + *@exception LockException special exception defined by a later + * implementation + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public int acquire () throws LockException, InterruptedException; + + /** + * Acquire ownership of the lock by the given absolute time time-out. + * A value of null for the timeout parameter results in a blocking + * acquire. + * A value of TimeValue.zero throws a TimeoutException if the + * acquire would block. + * <P> + *@param timeout absolute time by which the lock must be acquired + *@return appropriate Lock return value (AbstractLock.FAILURE, + * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK) + *@exception LockException special exception defined by a later + * implementation + *@exception JACE.ASX.TimeoutException thrown when the lock is not + * obtained by the desired time + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + *@see AbstractLock#tryAcquire + */ + public int acquire (TimeValue timeout) + throws LockException, TimeoutException, InterruptedException; + + /** + * Acquire a read lock, blocking indefinitely if necessary. This can + * be used to implement Reader-Writer locks in which multiple readers + * may have simultaneous access. + * <P> + *@return AbstractLock.FAILURE or AbstractLock.SUCCESS + *@exception LockException special exception defined by a later + * implementation + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public int acquireRead () throws LockException, InterruptedException; + + /** + * Acquire a read lock by the given absolute time time-out. This can + * be used to implement Reader-Writer locks in which multiple readers + * may have simultaneous access. + * <P> + *@param timeout absolute time by which the lock must be acquired + *@return appropriate lock return value (AbstractLock.FAILURE, + * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK) + *@exception LockException special exception defined by a later + * implementation + *@exception JACE.ASX.TimeoutException thrown when the lock is not + * obtained by the desired time + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + *@see AbstractLock#tryAcquireRead + */ + public int acquireRead (TimeValue timeout) + throws LockException, TimeoutException, InterruptedException; + + /** + * Acquire a write lock, blocking indefinitely if necessary. This can + * be used to implement Reader-Writer locks in which a writer has + * exclusive access. + * <P> + *@return AbstractLock.FAILURE or AbstractLock.SUCCESS + *@exception LockException special exception defined by a later + * implementation + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public int acquireWrite () throws LockException, InterruptedException; + + /** + * Acquire a write lock by the given absolute time time-out. This can + * be used to implement Reader-Writer locks in which a writer has + * exclusive access. + * <P> + *@param timeout absolute time by which the lock must be acquired + *@return appropriate AbstractLock return value (AbstractLock.FAILURE, + * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK) + *@exception LockException special exception defined by a later + * implementation + *@exception JACE.ASX.TimeoutException thrown when the lock is not + * obtained by the desired time + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + *@see AbstractLock#tryAcquireWrite + */ + public int acquireWrite (TimeValue timeout) + throws LockException, TimeoutException, InterruptedException; + + /** + * Give up the lock to some number of waiting threads (if any), then + * reacquire, blocking indefinitely if necessary. + * <P> + * An optimized method that efficiently reacquires the token if no + * other threads are waiting. This is useful for situations where + * you don't want to degrade the quality of service if there are + * other threads waiting to get the token. + * <P> + *@param requeuePosition position in the waiters queue to insert + * this thread. If this value is -1 and there are other + * threads waiting to obtain the token, this thread is queued + * at the end. If this value is greater than -1, then it + * indicates how many entries to skip over before inserting + * our thread into the queue. (For example, if it is 0, + * this thread is put at the front of the queue.) If this + * value is greater than the number of waiters, this thread is + * simply put at the end of the current waiters queue. + *@return AbstractLock.FAILURE or AbstractLock.SUCCESS + *@exception LockException special exception defined by a later + * implementation + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public int renew (int requeuePosition) throws LockException, + InterruptedException; + + /** + * Give up the lock to some waiting threads (if any), then reacquire + * by the given absolute time time-out. + * <P> + * An optimized method that efficiently reacquires the token if no + * other threads are waiting. This is useful for situations where + * you don't want to degrade the quality of service if there are + * other threads waiting to get the token. + * <P> + * A value of null for the timeout should indicate a blocking renew. + * <P> + *@param requeuePosition position in the waiters queue to insert + * this thread. If this value is -1 and there are other + * threads waiting to obtain the token, this thread is queued + * at the end. If this value is greater than -1, then it + * indicates how many entries to skip over before inserting + * our thread into the queue. (For example, if it is 0, + * this thread is put at the front of the queue.) If this + * value is greater than the number of waiters, this thread is + * simply put at the end of the current waiters queue. + * + *@param timeout absolute time by which the lock must be reacquired + * + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + *@exception LockException special exception defined by a later + * implementation + *@exception JACE.ASX.TimeoutException thrown when the lock is not + * obtained by the desired time + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public int renew (int requeuePosition, TimeValue timeout) + throws LockException, TimeoutException, InterruptedException; + + /** + * Try to acquire the lock without blocking. + * <P> + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + *@exception LockException special exception defined by a later + * implementation + */ + public int tryAcquire () throws LockException; + + /** + * Try to acquire a read lock without blocking. + * <P> + *@see #acquireRead + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + *@exception LockException special exception defined by a later + * implementation + */ + public int tryAcquireRead () throws LockException; + + /** + * Try to acquire a write lock without blocking. + *<P> + *@see #acquireWrite + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + *@exception LockException special exception defined by a later + * implementation + */ + public int tryAcquireWrite () throws LockException; + + /** + * Method that is called before a thread goes to sleep in an + * acquire. This should be overridden by a subclass to define + * the appropriate behavior. + */ + public void sleepHook (); + + /** + * Release ownership of this lock. + * <P> + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + *@exception LockException special exception defined by a later + * implementation + */ + public int release () throws LockException; +} diff --git a/java/JACE/Concurrency/Condition.java b/java/JACE/Concurrency/Condition.java new file mode 100644 index 00000000000..1889f6e1edf --- /dev/null +++ b/java/JACE/Concurrency/Condition.java @@ -0,0 +1,124 @@ +/************************************************* + * + * = PACKAGE + * JACE.Concurrency + * + * = FILENAME + * Condition.java + * + *@author Irfan Pyarali + * + *************************************************/ +package JACE.Concurrency; + +import JACE.ASX.TimeoutException; +import JACE.ASX.TimeValue; + +/** + * Abstraction for <em>traditional</em> + * condition variable + * <P> + * This condition variable allows the use of one + * mutex between multiple conditions. + * This implementation is based on the C++ version of ACE. + */ +public class Condition +{ + /** + * Default constructor + *@param Mutex for synchronization + */ + public Condition (Mutex mutex) + { + mutex_ = mutex; + } + + /** + * Wait for condition to become signaled. + *@exception InterruptedException exception during wait + */ + public void Wait () + throws InterruptedException + { + waiters_++; + + try + { + mutex_.release(); + synchronized (waitObject_) { + waitObject_.wait (); + } + mutex_.acquire (); + } + finally + { + waiters_--; + } + } + + /** + * TimedWait for condition to become signaled. Note that the + * given TimeValue is an absolute time, not a relative time. + * + *@param tv Absolute time to wait until before timing out + *@exception TimeoutException wait timed out exception + *@exception InterruptedException exception during wait + */ + public void Wait (TimeValue tv) + throws TimeoutException, InterruptedException + { + waiters_++; + + try + { + mutex_.release(); + + synchronized (waitObject_) { + long start = System.currentTimeMillis(); + long waitTime = tv.getMilliTime() - start; + if (waitTime < 1) + throw new TimeoutException (); + waitObject_.wait (waitTime); + } + + mutex_.acquire (tv); + } + finally + { + waiters_--; + } + } + + /** + * Signal condition. Wake one waiter (if any). + */ + public void signal () + { + synchronized (waitObject_) { + waitObject_.notify (); + } + } + + /** + * Signal condition. Wake up all waiters (if any). + */ + public void broadcast () + { + synchronized (waitObject_) { + waitObject_.notifyAll (); + } + } + + /** + * Accessor to lock + *@return Mutex + */ + public Mutex mutex () + { + return mutex_; + } + + private int waiters_; + private Object waitObject_ = new Object (); + private Mutex mutex_; +} diff --git a/java/JACE/Concurrency/LockAdapter.java b/java/JACE/Concurrency/LockAdapter.java new file mode 100644 index 00000000000..db2e9de05c7 --- /dev/null +++ b/java/JACE/Concurrency/LockAdapter.java @@ -0,0 +1,262 @@ +/************************************************* + * + * = PACKAGE + * JACE.Concurrency + * + * = FILENAME + * Lock.java + * + *@author Everett Anderson + * + *************************************************/ +package JACE.Concurrency; + +import JACE.ASX.*; + +/** + * Abstract adapter class which provides useful default implementations + * for several methods in the AbstractLock interface, as well as + * protected helper functions for making sure only the owner + * can perform certain operations. + * + *@see JACE.Concurrency.AbstractLock + */ +public abstract class LockAdapter implements AbstractLock +{ + /** + * Default implementation that calls acquire (TimeValue) with a null + * timeout. + * + *@see AbstractLock#acquire + */ + public int acquire () throws InterruptedException + { + try { + return acquire (null); + } catch (TimeoutException e) { + // This should never happen + return AbstractLock.FAILURE; + } + } + + /** + * Acquire ownership of the lock by the given absolute time time-out. + * A value of null for the timeout parameter results in a blocking + * acquire. + * A value of TimeValue.zero throws a TimeoutException if the + * acquire would block. + * <P> + *@param timeout absolute time by which the lock must be acquired + *@return appropriate Lock return value (AbstractLock.FAILURE, + * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK) + *@exception JACE.ASX.TimeoutException thrown when the lock is not + * obtained by the desired time + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + *@see AbstractLock#tryAcquire + */ + public abstract int acquire (TimeValue timeout) + throws TimeoutException, InterruptedException; + + /** + * Default implementation that calls acquireRead (TimeValue) with a + * null timeout. + * + *@see AbstractLock#acquireRead + */ + public int acquireRead () throws InterruptedException + { + try { + return acquireRead (null); + } catch (TimeoutException e) { + // This should never happen + } + + return AbstractLock.FAILURE; + } + + /** + * Default implementation that calls acquire (TimeValue). + * + *@see AbstractLock#acquireRead(TimeValue) + */ + public int acquireRead (TimeValue timeout) + throws TimeoutException, InterruptedException + { + return acquire (timeout); + } + + /** + * Default implementation that calls acquire with a null + * timeout. + * + *@see AbstractLock#acquireWrite + */ + public int acquireWrite () throws InterruptedException + { + try { + return acquire (null); + } catch (TimeoutException e) { + // This should never happen + } + + return AbstractLock.FAILURE; + } + + /** + * Default implementation that calls acquire (TimeValue). + * + *@see AbstractLock#acquireWrite(TimeValue) + */ + public int acquireWrite (TimeValue timeout) + throws TimeoutException, InterruptedException + { + return acquire (timeout); + } + + /** + * Default implementation that calls renew (int, TimeValue) with + * a null timeout. + * + *@see AbstractLock#renew(int) + */ + public int renew (int requeuePosition) throws InterruptedException + { + try + { + return renew (requeuePosition, null); + } catch (TimeoutException e) { + // Note that this should never happen since we requested a + // blocking acquire. + return AbstractLock.FAILURE; + } + } + + /** + * Give up the lock to some waiting threads (if any), then reacquire + * by the given absolute time time-out. + * <P> + * An optimized method that efficiently reacquires the token if no + * other threads are waiting. This is useful for situations where + * you don't want to degrade the quality of service if there are + * other threads waiting to get the token. + * <P> + * A value of null for the timeout should indicate a blocking renew. + * <P> + *@param requeuePosition position in the waiters queue to insert + * this thread. If this value is -1 and there are other + * threads waiting to obtain the token, this thread is queued + * at the end. If this value is greater than -1, then it + * indicates how many entries to skip over before inserting + * our thread into the queue. (For example, if it is 0, + * this thread is put at the front of the queue.) If this + * value is greater than the number of waiters, this thread is + * simply put at the end of the current waiters queue. + * + *@param timeout absolute time by which the lock must be reacquired + * + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + *@exception JACE.ASX.TimeoutException thrown when the lock is not + * obtained by the desired time + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public abstract int renew (int requeuePosition, + TimeValue timeout) + throws TimeoutException, + InterruptedException; + + /** + * Default implementation that calls tryAcquire (). + * + *@see AbstractLock#tryAcquireRead + */ + public int tryAcquireRead () + { + return tryAcquire (); + } + + /** + * Default implementation that calls tryAcquire (). + * + *@see AbstractLock#tryAcquireWrite + */ + public int tryAcquireWrite () + { + return tryAcquire (); + } + /** + * Try to acquire the lock without blocking. + * <P> + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + */ + public abstract int tryAcquire (); + + /** + * Default implementation as a no-op. + * + *@see AbstractLock#sleepHook + */ + public void sleepHook () + { + } + + /** + * Release ownership of this lock. + * <P> + *@return appropriate AbstractLock return value + * (AbstractLock.FAILURE or AbstractLock.SUCCESS) + */ + public abstract int release (); + + /** + * Obtains an Object which uniquely identifies the current accessor + * (usually a thread). This is used to make sure only an owner can + * perform certain operations like release. Subclasses can redefine + * the behavior as necessary, such as in the Token service where it is + * defined to be the client ID sent by the proxy. + * <P> + * When using Java 1.2 or later, it might be more efficient to use + * ThreadLocal and an Integer for the ID. The current default + * implementation returns the Thread.currentThread () reference. + * + *@return Object representing a unique ID for this accessor + */ + protected Object accessorID () + { + return Thread.currentThread(); + } + + /** + * Check to see if the current accessor is the (or a) owner of this + * lock. + */ + protected boolean isOwner() + { + return accessorID().equals(this.owner_); + } + + /** + * Set the current accessor to be the (or a) owner of this lock. + */ + protected void setOwner() + { + this.owner_ = accessorID(); + } + + /** + * Make sure that this accessor is no longer the (or a) owner of this + * lock. + */ + protected void clearOwner() + { + this.owner_ = null; + } + + /** + * Reference to the accessorID of the owner. + */ + private Object owner_; +} diff --git a/java/JACE/Concurrency/LockException.java b/java/JACE/Concurrency/LockException.java new file mode 100644 index 00000000000..dff4c09c626 --- /dev/null +++ b/java/JACE/Concurrency/LockException.java @@ -0,0 +1,28 @@ +package JACE.Concurrency; + +/** + * Base class for possible exceptions thrown from Lock + * mechanisms. This can be used by later Lock + * implementations to signal special types of exceptions, such + * as a remote failure, etc. + * <P> + */ +public class LockException extends java.lang.Exception +{ + /** + * Default constructor + */ + public LockException () { } + + /** + * Constructor with a string message that will be returned + * via the getMessage() method on Exception. + * <P> + *@see java.lang.Exception#getMessage + */ + public LockException (String message) + { + super(message); + } +} + diff --git a/java/JACE/Concurrency/Mutex.java b/java/JACE/Concurrency/Mutex.java new file mode 100644 index 00000000000..856fdbd79eb --- /dev/null +++ b/java/JACE/Concurrency/Mutex.java @@ -0,0 +1,239 @@ +/************************************************* + * + * = PACKAGE + * JACE.Concurrency + * + * = FILENAME + * Mutex.java + * + *@author Prashant Jain + *@author Everett Anderson + * + *************************************************/ +package JACE.Concurrency; + +import java.util.*; +import JACE.ASX.*; + +/** + * Value added abstraction for mutex variable creation. + * + * A mutex whose operations do not block forever and can time out. + * <P> + * <EM>This class does not support recursive semantics.</EM> + */ +public class Mutex extends LockAdapter +{ + /** + * Acquire ownership of the lock, blocking indefinitely if necessary. + * <P> + *@return AbstractLock.FAILURE or AbstractLock.SUCCESS + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public synchronized int acquire () throws InterruptedException + { + if (this.monitor_.condition ()) { + this.monitor_.condition (false); + setOwner (); + return AbstractLock.SUCCESS; + } + + this.numberOfWaiters_++; + try { + sleepHook (); + this.monitor_.timedWait (); + } finally { + this.numberOfWaiters_--; + } + this.monitor_.condition (false); + setOwner(); + + return AbstractLock.SLEEPHOOK; + } + + public int renew (int requeuePosition, + TimeValue timeout) + throws InterruptedException, + TimeoutException + { + RenewObject rwo; + + synchronized (this) { + + if (!this.isOwner ()) + return AbstractLock.FAILURE; + + if (numberOfWaiters_ == 0 || requeuePosition == 0) + return AbstractLock.SUCCESS; + + if (requeuePosition < 0 || requeuePosition > numberOfWaiters_) + requeuePosition = numberOfWaiters_; + + rwo = new RenewObject (requeuePosition); + + this.release (); + this.renewers_.addElement (rwo); + } + + // We can't have the method synchronized, or synchronize on (this) + // in here because then the Thread that was woken up won't be able + // to continue its acquire. + // + // Normally when an exception occurs in timedWait, this thread just + // needs to remove itself from the renewers queue. + // + // However, the following situation exists: + // Thread A is the current owner, and is doing processing in release() + // This thread generates a timeout exception in timedWait + // Thread A signals this thread to wake up and take ownership, and + // removes it from the queue. + // This thread never takes ownership -- the exception keeps going up. + // + // This could lead to other renewers waiting in limbo forever. + // + // Solution: If this thread has an exception and it looks like it + // has been proclaimed the owner, then it calls release and lets + // the exception continue. + + boolean exceptionOccured = true; + try { + synchronized (rwo) { + rwo.timedWait (timeout); + + exceptionOccured = false; + } + } finally { + if (exceptionOccured) { + synchronized (this) { + if (!renewers_.removeElement (rwo)) { + setOwner (); + release (); + } + } + } + } + + synchronized (this) { + setOwner (); + } + + // By this point, we should know that we have the lock. The condition + // flag is never set to true in the release() call from the Thread + // that gave us control. + + return AbstractLock.SUCCESS; + } + + public synchronized int tryAcquire () { + if (this.monitor_.condition ()) { + this.monitor_.condition (false); + setOwner(); + return AbstractLock.SUCCESS; + } else + return AbstractLock.FAILURE; + } + + public synchronized int acquire (TimeValue tv) + throws TimeoutException, InterruptedException + { + if (this.monitor_.condition ()) { + this.monitor_.condition (false); + setOwner (); + return AbstractLock.SUCCESS; + } + + this.numberOfWaiters_++; + try { + sleepHook (); + this.monitor_.timedWait (tv); + } finally { + this.numberOfWaiters_--; + } + this.monitor_.condition (false); + setOwner(); + + return AbstractLock.SLEEPHOOK; + } + + /** + * Checks any objects in the renewers queue, giving one of them + * the lock if it is appropriate. Assumes the synchronization + * lock is already held. + * + *@return true if a renewer was signaled, else false + */ + protected boolean signalNextRenewer () + { + // First find the renewer with the minimum yieldTo count, processing + // all of them along the way. + if (this.renewers_.size() > 0) { + + RenewObject renewer = (RenewObject)renewers_. + elementAt (renewers_.size () - 1); + + renewer.decrementYieldTo (); + + for (int i = this.renewers_.size() - 2; i >=0; i--) { + + RenewObject rwo = (RenewObject)renewers_.elementAt (i); + + rwo.decrementYieldTo (); + + renewer = renewer.min (rwo); + } + + // If the renewer with the minimum yieldTo count has yielded to + // enough threads, or if there are no waiting threads, it should + // be signaled (thus, it wakes up and obtains the lock again). + + if (renewer.condition () || numberOfWaiters_ == 0) { + // Note that we leave monitor_.condition in the false state so + // we are assured that only the renewer (and not another + // Thread that does an acquire) will gain control. This + // is important since the renew method can't be synchronized + // in its current implementation. + renewers_.removeElement(renewer); + + synchronized (renewer) { + renewer.signal (); + } + + return true; + } + } + + return false; + } + + public synchronized int release () + { + if (!isOwner()) + return AbstractLock.FAILURE; + + if (!signalNextRenewer ()) { + // Do a normal release if there are no threads waiting to renew + // or no such threads are ready to renew. + this.monitor_.condition (true); + this.monitor_.signal (); + } + + return AbstractLock.SUCCESS; + } + + /** + * Monitor used to signal whether or not this Mutex is available. + */ + protected WaitObject monitor_ = new WaitObject (true, this); + // The monitor (adapter) to wait on + + /** + * Queue of waiting renewers. + */ + protected Vector renewers_ = new Vector (); + + /** + * Number of waiting threads. + */ + protected int numberOfWaiters_ = 0; +} diff --git a/java/JACE/Concurrency/RWMutex.java b/java/JACE/Concurrency/RWMutex.java new file mode 100644 index 00000000000..abb30ce3bc8 --- /dev/null +++ b/java/JACE/Concurrency/RWMutex.java @@ -0,0 +1,268 @@ +package JACE.Concurrency; + +import java.util.*; +import JACE.ASX.*; + +/** + * A read/write lock allows multiple + * readers or a single writer to access the guarded element. + * <P> + * <EM>This class does not support recursive semantics.</EM> + */ +public class RWMutex extends LockAdapter +{ + public synchronized int tryAcquire () + { + if (referenceCount_ == 0) { + referenceCount_ = -1; + setOwner (); + return AbstractLock.SUCCESS; + } else + return AbstractLock.FAILURE; + } + + public synchronized int tryAcquireRead () + { + if (referenceCount_ > -1 && waiters_.size () == 0) { + referenceCount_++; + setOwner (); + return AbstractLock.SUCCESS; + } else + return AbstractLock.FAILURE; + } + + public int acquire(TimeValue timeout) + throws TimeoutException, InterruptedException + { + return acquireWrite(timeout); + } + + public void waitUntilIsOwner (RWWaitObject waitObj, TimeValue timeout) + throws TimeoutException, InterruptedException + { + boolean exceptionOccured = true; + try { + sleepHook (); + synchronized (waitObj) { + waitObj.timedWait (timeout); + } + exceptionOccured = false; + } finally { + + synchronized (this) { + + if (exceptionOccured) { + if (!waiters_.removeElement (waitObj)) { + setOwner (); + release (); + } + } else + setOwner(); + } + } + } + + public int acquireRead(TimeValue timeout) + throws TimeoutException, InterruptedException + { + RWWaitObject waitObj = null; + + synchronized (this) { + + if (referenceCount_ > -1 && waiters_.size () == 0) { + referenceCount_++; + setOwner (); + return AbstractLock.SUCCESS; + } + + waitObj = new RWWaitObject (true); + + waiters_.addElement (waitObj); + } + + waitUntilIsOwner (waitObj, timeout); + + return AbstractLock.SLEEPHOOK; + } + + public int acquireWrite(TimeValue timeout) + throws TimeoutException, InterruptedException + { + RWWaitObject waitObj = null; + + synchronized (this) { + + if (referenceCount_ == 0) { + referenceCount_ = -1; + setOwner (); + return AbstractLock.SUCCESS; + } + + waitObj = new RWWaitObject (false); + + waiters_.addElement (waitObj); + } + + waitUntilIsOwner (waitObj, timeout); + + // When the writer gets here, it has been cleared to go by + // whatever thread specifically gave control to this writer in + // release. The referenceCount_ and numberOfWaitingWriters_ + // variables are also adjusted by the releasing thread since + // it already has a synchronization lock. Not doing that, + // and then having another synchronized (this) block in here + // could lead to a situation in which another thread sneaks + // in inbetween when this thread leaves timedWait and goes to + // adjust them. + + return AbstractLock.SLEEPHOOK; + } + + + public synchronized int release () + { + if (!isOwner ()) + return AbstractLock.FAILURE; + + clearOwner (); + + // Releasing a reader. + if (referenceCount_ > 0) { + referenceCount_--; + + if (referenceCount_ != 0) + return AbstractLock.SUCCESS; + + } else { + // releasing a writer + referenceCount_ = 0; + } + + if (waiters_.size () == 0) + return AbstractLock.SUCCESS; + + if (releaseFirstReaders () == 0) { + RWWaitObject waitObj = (RWWaitObject)waiters_.firstElement (); + waiters_.removeElementAt (0); + + referenceCount_ = -1; + + waitObj.condition (true); + synchronized (waitObj) { + waitObj.signal (); + } + } + + return AbstractLock.SUCCESS; + } + + // Releases all waiting readers up to the first waiting writer + // or the end of the queue. Returns the number of readers + // released. + protected int releaseFirstReaders () + { + int releasedReaders = 0; + + do { + + RWWaitObject waitObj = (RWWaitObject)waiters_.firstElement (); + if (!waitObj.isReader ()) + break; + + waiters_.removeElementAt (0); + + referenceCount_++; + releasedReaders++; + + waitObj.condition (true); + synchronized (waitObj) { + waitObj.signal (); + } + + } while (waiters_.size () > 0); + + return releasedReaders; + } + + public int renew (int requeuePosition, + JACE.ASX.TimeValue timeout) + throws InterruptedException, + TimeoutException + { + RWWaitObject waitObj = null; + + synchronized (this) { + + if (!isOwner ()) + return AbstractLock.FAILURE; + + if (requeuePosition == 0 || waiters_.size () == 0) + return AbstractLock.SUCCESS; + + waitObj = new RWWaitObject (referenceCount_ > 0); + + if (requeuePosition < 0 || requeuePosition > waiters_.size ()) { + requeuePosition = waiters_.size (); + } + + waiters_.insertElementAt (waitObj, requeuePosition); + + release (); + } + + waitUntilIsOwner (waitObj, timeout); + + // When the writer gets here, it has been cleared to go by + // whatever thread specifically gave control to this writer in + // release. The referenceCount_ and numberOfWaitingWriters_ + // variables are also adjusted by the releasing thread since + // it already has a synchronization lock. Not doing that, + // and then having another synchronized (this) block in here + // could lead to a situation in which another thread sneaks + // in inbetween when this thread leaves timedWait and goes to + // adjust them. + + return AbstractLock.SUCCESS; + } + + static class RWWaitObject extends WaitObject + { + public RWWaitObject (boolean isReader) + { + isReader_ = isReader; + } + + public boolean isReader () + { + return isReader_; + } + + private boolean isReader_ = false; + } + + protected boolean isOwner () + { + return owners_.containsKey (accessorID()); + } + + protected void setOwner () + { + owners_.put (accessorID(), this); + } + + protected void clearOwner () + { + owners_.remove (accessorID()); + } + + private Vector waiters_ = new Vector (); + + private int referenceCount_ = 0; + // Value is -1 if writer has the lock, else this keeps track of the + // number of readers holding the lock. + + private Hashtable owners_ = new Hashtable (); + + private int nestingLevel_ = 0; +} + diff --git a/java/JACE/Concurrency/RenewObject.java b/java/JACE/Concurrency/RenewObject.java new file mode 100644 index 00000000000..b690958968a --- /dev/null +++ b/java/JACE/Concurrency/RenewObject.java @@ -0,0 +1,36 @@ +package JACE.Concurrency; + +import JACE.ASX.TimedWait; + +class RenewObject extends TimedWait +{ + public RenewObject (int maxYieldTo) + { + yieldTo_ = maxYieldTo; + } + + public boolean condition () + { + return yieldTo_ <= 0; + } + + public void decrementYieldTo() + { + this.yieldTo_--; + } + + public int yieldTo () + { + return this.yieldTo_; + } + + public RenewObject min (RenewObject other) + { + if (other.yieldTo_ < this.yieldTo_) + return other; + else + return this; + } + + private int yieldTo_; +} diff --git a/java/JACE/Concurrency/Semaphore.java b/java/JACE/Concurrency/Semaphore.java new file mode 100644 index 00000000000..5e558035aee --- /dev/null +++ b/java/JACE/Concurrency/Semaphore.java @@ -0,0 +1,263 @@ +/************************************************* + * + * = PACKAGE + * JACE.Concurrency + * + * = FILENAME + * Semaphore.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Concurrency; + +import java.util.*; +import JACE.ASX.*; + +/** + * Implementation of Dijkstra's counting semaphore in java. + * <P> + * <EM>This class does not support recursive semantics.</EM> + */ +public class Semaphore extends LockAdapter +{ + static class TimedWaitSAdapter extends JACE.ASX.TimedWait + { + TimedWaitSAdapter (Object obj) + { + super (obj); + } + + // Check to see if there are any semaphores available. + public boolean condition () + { + return this.count_ > 0; + } + + // Increment the count by one + public void increment () + { + this.count_++; + } + + // Decrement the count by one + public void decrement () + { + this.count_--; + } + + // Set the count + public void count (int c) + { + this.count_ = c; + } + + public int count () + { + return this.count_; + } + + private int count_ = 0; + } + + /** + * Create a Semaphore. + *@param count semaphore count + */ + public Semaphore (int c) + { + this.monitor_.count (c); + this.owners_ = new Hashtable (c); + } + + /** + * Create a binary Semaphore. + */ + public Semaphore () + { + this.monitor_.count (1); + this.owners_ = new Hashtable (1); + } + + public synchronized int tryAcquire () + { + if (this.monitor_.condition ()) { + this.monitor_.decrement (); + setOwner (); + return AbstractLock.SUCCESS; + } else + return AbstractLock.FAILURE; + } + + /** + * Acquire the Semaphore. Throws a TimeoutException if the semaphore + * isn't acquired before the given absolute time. + *@param tv time (TimeValue) to wait until before throwing a + * TimeoutException (unless the semaphore is acquired before that) + *@exception TimeoutException wait timed out exception + *@exception InterruptedException exception during wait + */ + public synchronized int acquire (TimeValue tv) + throws TimeoutException, InterruptedException + { + if (this.monitor_.condition ()) { + this.monitor_.decrement (); + setOwner (); + return AbstractLock.SUCCESS; + } + + numberOfWaiters_++; + + try { + sleepHook (); + this.monitor_.timedWait (tv); + } finally { + numberOfWaiters_--; + } + + this.monitor_.decrement (); + setOwner (); + + return AbstractLock.SLEEPHOOK; + } + + public synchronized int release () + { + if (!isOwner ()) + return AbstractLock.FAILURE; + + if (!signalNextRenewer ()) { + this.monitor_.increment (); + this.monitor_.signal (); + clearOwner (); + } + + return AbstractLock.SUCCESS; + } + + /** + * Checks any objects in the renewers queue, giving one of them + * the lock if it is appropriate. Assumes the synchronization + * lock is already held. + * + *@return true if a renewer was signaled, else false + */ + protected boolean signalNextRenewer () + { + // First find the renewer with the minimum yieldTo count, processing + // all of them along the way. + if (this.renewers_.size() > 0) { + + RenewObject renewer = (RenewObject)renewers_. + elementAt (renewers_.size () - 1); + + renewer.decrementYieldTo (); + + for (int i = this.renewers_.size() - 2; i >=0; i--) { + + RenewObject rwo = (RenewObject)renewers_.elementAt (i); + + rwo.decrementYieldTo (); + + renewer = renewer.min (rwo); + } + + // If the renewer with the minimum yieldTo count has yielded to + // enough threads, or if there are no waiting threads, it should + // be signaled (thus, it wakes up and obtains the lock again). + + if (renewer.condition () || numberOfWaiters_ == 0) { + // Note that we leave monitor_.inUse in the true state so + // we are assured that only the renewer (and not another + // Thread that does an acquire) will gain control. This + // is important since the renew method can't be synchronized + // in its current implementation. + renewers_.removeElement(renewer); + + synchronized (renewer) { + renewer.signal (); + } + + return true; + } + } + + return false; + } + + public int renew (int requeuePosition, + JACE.ASX.TimeValue timeout) + throws InterruptedException, + TimeoutException + { + RenewObject rwo; + + synchronized (this) { + + if (!this.isOwner ()) + return AbstractLock.FAILURE; + + if (numberOfWaiters_ == 0 || + requeuePosition == 0 || + this.monitor_.condition ()) + return AbstractLock.SUCCESS; + + if (requeuePosition < 0 || requeuePosition > numberOfWaiters_) + requeuePosition = numberOfWaiters_; + + rwo = new RenewObject (requeuePosition); + + this.release (); + this.renewers_.addElement (rwo); + } + + boolean exceptionOccured = true; + try { + synchronized (rwo) { + rwo.timedWait (timeout); + + exceptionOccured = false; + } + } finally { + synchronized (this) { + + if (exceptionOccured) { + if (!renewers_.removeElement (rwo)) { + setOwner (); + release (); + } + } else { + setOwner(); + } + } + } + + // By this point, we should know that we have the lock. The inUse + // flag is never set to false in the release() call from the Thread + // that gave us control. That thread also set the owner value. + + return AbstractLock.SUCCESS; + } + + protected boolean isOwner () + { + return owners_.containsKey (accessorID()); + } + + protected void setOwner () + { + owners_.put (accessorID(), this); + } + + protected void clearOwner () + { + owners_.remove (accessorID()); + } + + private TimedWaitSAdapter monitor_ = new TimedWaitSAdapter (this); + // The monitor (adapter) to wait on + + private Hashtable owners_; + private Vector renewers_ = new Vector (); + private int numberOfWaiters_ = 0; +} diff --git a/java/JACE/Concurrency/ThreadManager.java b/java/JACE/Concurrency/ThreadManager.java new file mode 100644 index 00000000000..d23e2410676 --- /dev/null +++ b/java/JACE/Concurrency/ThreadManager.java @@ -0,0 +1,113 @@ +/************************************************* + * + * = PACKAGE + * JACE.Concurrency + * + * = FILENAME + * ThreadManager.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Concurrency; + +import java.util.*; +import JACE.OS.*; + +/** + * Wrapper for a ThreadGroup which provides additional methods for + * creating a certain number of Runnable instances. + */ +public class ThreadManager +{ + /** + * Default constructor + */ + public ThreadManager () + { + this (ACE.DEFAULT_THREAD_GROUP_NAME); + } + + /** + * Create a Thread Manager. + *@param groupName name of the thread group that the Thread Manager + * will manage + */ + public ThreadManager (String groupName) + { + this.thrGrp_ = new ThreadGroup (groupName); + if (this.thrGrp_ == null) + ACE.ERROR ("Thread group create failed"); + } + + /** + * Create a new thread. + *@param thr the caller whose run method will be invoked when the + * thread has been spawned + *@param daemon flag indicating whether the thread should be + * spawned off as a daemon thread + */ + public void spawn (Runnable thr, + boolean daemon) + { + Thread t = new Thread (this.thrGrp_, thr); + if (daemon) // Set the thread to be a daemon thread + t.setDaemon (true); + t.start (); + } + + /** + * Create a new thread and also give it a name. + *@param thr the caller whose run method will be invoked when the + * thread has been spawned + *@param threadName the name of the new thread + *@param daemon flag indicating whether the thread should be + * spawned off as a daemon thread + */ + public void spawn (Runnable thr, + String threadName, + boolean daemon) + { + Thread t = new Thread (this.thrGrp_, thr, threadName); + if (daemon) // Set the thread to be a daemon thread + t.setDaemon (true); + t.start (); + } + + + /** + * Create <n> new threads. + *@param n the number of threads to spawn + *@param thr the caller whose run method will be invoked by each of + * the <n> threads + *@param daemon flag indicating whether the threads should be + * spawned off as daemon threads + */ + public void spawnN (int n, + Runnable thr, + boolean daemon) + { + // Spawn off all the threads. + for (int i = 0; i < n; i++) + { + this.spawn (thr, daemon); + } + } + + /** + * Get the thread group containing all the threads. Note that the + * thread group can be used to get information regarding number of + * active threads as well as to suspend/resume all the threads in + * the group. + *@return the thread group that contains all the threads managed by + * the Thread Manager + */ + public ThreadGroup thrGrp () + { + return this.thrGrp_; + } + + private ThreadGroup thrGrp_; + // Thread Group that contains all the spawned threads + +} diff --git a/java/JACE/Concurrency/Token.java b/java/JACE/Concurrency/Token.java new file mode 100644 index 00000000000..c9080b47fbe --- /dev/null +++ b/java/JACE/Concurrency/Token.java @@ -0,0 +1,301 @@ +/************************************************* + * + * = PACKAGE + * JACE.Concurrency + * + * = FILENAME + * Token.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Concurrency; + +import java.util.*; +import JACE.ASX.*; + +import JACE.OS.*; + +/** + * Class that acquires, renews, and releases a synchronization + * token that is serviced in strict FIFO ordering. + * <P> + * This is a general-purpose synchronization mechanism that offers + * several benefits. For example, it implements "recursive mutex" + * semantics, where a thread that owns the token can reacquire it + * without deadlocking. In addition, threads that are blocked + * awaiting the token are serviced in strict FIFO order as other + * threads release the token. The solution makes use of the + * Specific Notification pattern presented by Tom Cargill in + * "Specific Notification for Java Thread Synchronization," PLoP96. + * + * <P> + * This class DOES support recursive semantics. + */ +public class Token extends LockAdapter +{ + /** + * Acquire ownership of the lock, blocking indefinitely if necessary. + * <P> + *@return AbstractLock.FAILURE or AbstractLock.SUCCESS + *@exception InterruptedException indicates another thread has + * interrupted this one during wait + */ + public int acquire () throws InterruptedException + { + try + { + return this.acquire (null); + } + catch (TimeoutException e) + { + // This really shouldn't happen since we are supposed to + // block. + return AbstractLock.FAILURE; + } + } + + /** + * Acquire the token by the given absolute time time-out. The + * method uses synchronized blocks internally to avoid race conditions. + *@param timeout time to wait until before throwing a + * TimeoutException (unless the token is acquired before that). + * Performs a blocking acquire if the given timeout is null. + *@return AbstractLock.SUCCESS if acquires without calling <sleepHook> + * AbstractLock.SLEEPHOOK if <sleepHook> is called. + * AbstractLock.FAILURE if failure occurs + *@exception TimeoutException if time-out occurs + *@exception InterruptedException exception during wait + */ + public int acquire (TimeValue timeout) throws TimeoutException, + InterruptedException + { + int result = AbstractLock.SUCCESS; + WaitObject snl = new WaitObject (); + boolean mustWait; + synchronized (snl) + { + synchronized (this) + { + mustWait = !this.snq_.isEmpty (); + + if (mustWait && isOwner ()) + { + // I am the one who has the token. So just increment + // the nesting level + this.nestingLevel_++; + return AbstractLock.SUCCESS; + } + // Add local lock to the queue + this.snq_.addElement (snl); + } + if (mustWait) + { + result = AbstractLock.SLEEPHOOK; + sleepHook(); + + boolean exceptionOccured = true; + try { + snl.timedWait(timeout); + exceptionOccured = false; + } finally { + if (exceptionOccured) { + synchronized (this) { + if (!snq_.removeElement (snl)) { + setOwner (); + release (); + } + } + } + } + } + + // Set the owner of the token + synchronized (this) { + setOwner(); + } + } + + return result; + } + + /** + * Try to acquire the token. Implements a non-blocking acquire. + * + *@return AbstractLock.SUCCESS if acquires + * AbstractLock.FAILURE if failure occurs + */ + public synchronized int tryAcquire () + { + int result = AbstractLock.SUCCESS; + + if (this.snq_.isEmpty ()) + { + // No one has the token, so acquire it + this.snq_.addElement (new WaitObject ()); + + setOwner(); + } + else if (isOwner()) + { + this.nestingLevel_++; + } + // Someone else has the token. + else + { + // Would have to block to acquire the token, so return + // failure. + result = AbstractLock.FAILURE; + } + return result; + } + + /** + * An optimized method that efficiently reacquires the token if no + * other threads are waiting. This is useful for situations where + * you don't want to degrade the quality of service if there are + * other threads waiting to get the token. If the given TimeValue + * is null, it's the same as calling renew(int requeuePosition). + *@param requeuePosition Position in the queue where to insert the + * lock. If requeuePosition == -1 and there are other threads + * waiting to obtain the token we are queued at the end of the list + * of waiters. If requeuePosition > -1 then it indicates how many + * entries to skip over before inserting our thread into the list of + * waiters (e.g.,requeuePosition == 0 means "insert at front of the + * queue"). + *@param timeout Throw a TimeoutException if the token isn't renewed + * before this absolute time timeout. + *@return AbstractLock.SUCCESS if renewed the lock + * AbstractLock.FAILURE if failure occurs + *@exception TimeoutException exception if timeout occurs + *@exception InterruptedException exception during wait + */ + public int renew (int requeuePosition, TimeValue timeout) + throws TimeoutException, InterruptedException + { + WaitObject snl = null; + int saveNestingLevel = 0; + + synchronized (this) + { + if (!isOwner ()) + return AbstractLock.FAILURE; + + // Check if there is a thread waiting to acquire the token. If + // not or if requeuePosition == 0, then we don't do anything + // and we simply keep the token. + if (this.snq_.size () > 1 && requeuePosition != 0) + { + // Save the nesting level + saveNestingLevel = this.nestingLevel_; + this.nestingLevel_ = 0; + + // Reinsert ourselves at requeuePosition in the queue + snl = (WaitObject) this.snq_.firstElement (); + this.snq_.removeElementAt (0); + + if (requeuePosition < 0) + this.snq_.addElement (snl); // Insert at end + else + this.snq_.insertElementAt (snl, Math.min(requeuePosition, + this.snq_.size())); + + synchronized (this.snq_.firstElement ()) + { + // Notify the first waiting thread in the queue + WaitObject obj = (WaitObject) this.snq_.firstElement (); + // Set its condition to be true so that it falls out + // of the for loop + obj.condition (true); + // Now signal the thread + obj.signal (); + } + } + } + + // Check if we reinserted the lock in the queue and therefore need + // to do a wait + if (snl != null) + { + synchronized (snl) + { + // Set the condition to be false so that we can begin the + // wait + snl.condition (false); + // Wait until the given absolute time (or until notified + // if the timeout is null) + + boolean exceptionOccured = true; + try { + + snl.timedWait (timeout); + + exceptionOccured = false; + + } finally { + if (exceptionOccured) { + synchronized (this) { + if (!snq_.removeElement (snl)) { + setOwner (); + release (); + } + } + } + } + } + + synchronized (this) { + // Restore the nesting level and current owner of the lock + this.nestingLevel_ = saveNestingLevel; + + // Set the owner of the token + setOwner(); + } + } + + return AbstractLock.SUCCESS; + } + + /** + * Release the token. It is safe for non-owners to call + * this. + *@return AbstractLock.SUCCESS on success + * AbstractLock.FAILURE on failure (for instance, a non-owner + * calling release) + */ + public synchronized int release () + { + if (!isOwner()) + return AbstractLock.FAILURE; + + // Check if nestingLevel > 0 and if so, decrement it + if (this.nestingLevel_ > 0) + this.nestingLevel_--; + else + { + clearOwner (); + this.snq_.removeElementAt (0); + if (!this.snq_.isEmpty ()) + { + synchronized (this.snq_.firstElement ()) + { + // Notify the first waiting thread in the queue + WaitObject obj = (WaitObject) this.snq_.firstElement (); + // Set its condition to be true so that it falls out + // of the for loop + obj.condition (true); + // Now signal the thread + obj.signal (); + } + } + } + + return AbstractLock.SUCCESS; + } + + private Vector snq_ = new Vector (); + // Vector of lock objects + + private int nestingLevel_ = 0; + // Current Nesting Level +} diff --git a/java/JACE/Concurrency/WaitObject.java b/java/JACE/Concurrency/WaitObject.java new file mode 100644 index 00000000000..b7c8cbc7191 --- /dev/null +++ b/java/JACE/Concurrency/WaitObject.java @@ -0,0 +1,39 @@ +package JACE.Concurrency; + +import JACE.ASX.TimedWait; + +class WaitObject extends TimedWait +{ + public WaitObject () + { + super (); + } + + public WaitObject (Object obj) + { + super (obj); + } + + public WaitObject (boolean initialState) + { + condition_ = initialState; + } + + public WaitObject (boolean initialState, Object obj) + { + super (obj); + condition_ = initialState; + } + + public boolean condition () + { + return this.condition_; + } + + public void condition (boolean c) + { + this.condition_ = c; + } + + private boolean condition_ = false; +} diff --git a/java/JACE/Concurrency/package.html b/java/JACE/Concurrency/package.html new file mode 100644 index 00000000000..ceadb36f662 --- /dev/null +++ b/java/JACE/Concurrency/package.html @@ -0,0 +1,15 @@ +<!-- $Id$ --> +<HTML> +<BODY> +Collection of concurrency mechanisms and a Thread manager. +<P> +JACE concurrency mechanisms now inherit from a common base class, +AbstractLock. This allows users to write code without regard to +whether a lock is local or remote. + +@see JACE.netsvcs.Token.RemoteLock +@see <a href="http://www.cs.wustl.edu/~schmidt/ACE-papers.html#concurrency">Documents on ACE concurrency components</a> +</BODY> +</HTML> + + |