[concurrency-interest] fast semaphore

Joseph Seigh jseigh_cp00 at xemaps.com
Thu Apr 5 06:40:33 EDT 2007


Here's the fast pathed semaphore I used with ConcurrentLinkedQueue.
It only does acquires and releases of single permits though it would be
easy to make it release multiple permits.  Acquiring multiple permits would
be a little tricky based on the current Semaphore semantics (atomic acquire
of all requested permits).

It's a port from a C win32/posix version that's been around for a while.

-
Joe Seigh
-


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

public class FastSemaphore {
   
    AtomicInteger     count;        // semaphore count
    AtomicInteger    cancel;        // deferred cancelation count
    Semaphore        sem;        // slow semaphore

    public FastSemaphore(int z, boolean fair) {
        count = new AtomicInteger(z);
        cancel = new AtomicInteger(0);
        sem = new Semaphore(0, fair);
    }
   
    /*
     * processCancels - add cancelCount to current count
     *
     *   increment count by min(cancelCount, -(count)) iff count < 0
     */
    void processCancels(int cancelCount) {
        int    oldCount;
        int newCount;
       
        if (cancelCount > 0) {
            while ((oldCount = count.get()) < 0) {
                if ((newCount = oldCount + cancelCount) > 0)
                    newCount = 0;
               
                if (count.compareAndSet(oldCount, newCount)) {
                    cancelCount -= (newCount - oldCount);        // 
update cancelCount           
                    break;
                }               
            }
        }
       
        // add any untransferred cancelCount back into cancel
        if (cancelCount > 0) {
            cancel.addAndGet(cancelCount);
        }       
    }
   
    public void acquire()
    throws InterruptedException
    {
        if (count.addAndGet(-1) < 0) {
            try {
                sem.acquire();
            }
           
            catch (InterruptedException e) {
                // uncomment one and only one of the following 2 statements
                cancel.incrementAndGet();
                // processCancels(1);
                throw e;
            }
        }
    }
   
    public boolean tryAcquire(long timeout, TimeUnit unit)
    throws InterruptedException
    {
        boolean rc;
        if (count.addAndGet(-1) < 0) {
            try {
                rc = sem.tryAcquire(timeout, unit);               
            }
           
            catch (InterruptedException e) {
                // uncomment one and only one of the following 2 statements
                cancel.incrementAndGet();
                // processCancels(1);
                throw e;
            }
           
            if (rc == false) {
                cancel.incrementAndGet();               
                // processCancels(1);
            }
            return rc;
        }
       
        else
            return true;
    }
   
    public boolean tryAcquire() {
        int    oldCount;
       
        do {
            oldCount = count.get();
        }
        while (oldCount > 0 && !count.compareAndSet(oldCount, (oldCount 
- 1)));
       
        return (oldCount > 0);
       
    }
   
    public void release() {
        if (cancel.get() > 0 && count.get() < 0) {
            processCancels(cancel.getAndSet(0));
        }
       
        if (count.addAndGet(1) <= 0) {
            sem.release();
        }
    }
   
}

/*-*/




More information about the Concurrency-interest mailing list