Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

ReentrantLock.d

Go to the documentation of this file.
00001 
00016 module mango.locks.ReentrantLock;
00017 
00018 import mango.locks.Lock;
00019 
00020 private {
00021   import std.thread;
00022 
00023   import mango.sys.Atomic;
00024 
00025   import mango.locks.Utils;
00026   import mango.locks.LockImpl;
00027   import mango.locks.Exceptions;
00028 }
00029 
00089 class ReentrantLock : Lock {
00090 
00092   private final Sync sync;
00093 
00094   /*
00095    * Base of synchronization control for this lock. Subclassed
00096    * into fair and nonfair versions below. Uses AbstractLock state to
00097    * represent the number of holds on the lock.
00098    */
00099   abstract class Sync : AbstractLock {
00100     /* Current owner thread */
00101     Thread owner;
00102 
00103     /*
00104      * Perform Lock.lock. The main reason for subclassing
00105      * is to allow fast path for nonfair version.
00106      */
00107     abstract void lock();
00108 
00109     /* 
00110      * Perform non-fair tryLock.  tryAcquire is
00111      * implemented in subclasses, but both need nonfair
00112      * try for trylock method
00113      */
00114     final bool nonfairTryAcquire(int acquires) { 
00115       Thread current = Thread.getThis();
00116       int c = state;
00117       if (c == 0) {
00118         if (Atomic.compareAndSet32(&state_, c, acquires)) {
00119           owner = current;
00120           return true;
00121         }
00122       }
00123       else if (current is owner) {
00124         state = c+acquires;
00125         return true;
00126       }
00127       return false;
00128     }
00129 
00130     final bool tryRelease(int releases) {
00131       if (Thread.getThis() !is owner)
00132         throw new IllegalArgumentException();
00133       int c = state - releases;
00134       bool free = false;
00135       if (c == 0) {
00136         free = true;
00137         owner = null;
00138       }
00139       state = c;
00140       return free;
00141     }
00142 
00143     final bool isHeldExclusively() {
00144       return state != 0 && owner is Thread.getThis();
00145     }
00146 
00147     final ConditionObject newCondition() {
00148       return new ConditionObject(this);
00149     }
00150 
00151     // Methods relayed from outer class
00152 
00153     final Thread getOwner() {
00154       int c = state;
00155       Thread o = owner;
00156       return (c == 0)? null : o;
00157     }
00158         
00159     final int getHoldCount() {
00160       int c = state;
00161       Thread o = owner;
00162       return (o is Thread.getThis())? c : 0;
00163     }
00164         
00165     final bool isLocked() {
00166       return state != 0;
00167     }
00168   }
00169 
00170   /*
00171    * Sync object for non-fair locks
00172    */
00173   final class NonfairSync : Sync {
00174     /*
00175      * Perform lock.  Try immediate barge, backing up to normal
00176      * acquire on failure.
00177      */
00178     final void lock() {
00179       if (Atomic.compareAndSet32(&state_, 0, 1))
00180         owner = Thread.getThis();
00181       else {
00182         acquire(1);
00183       }
00184     }
00185 
00186     protected final bool tryAcquire(int acquires) { 
00187       return nonfairTryAcquire(acquires);
00188     }
00189   }
00190 
00191   /*
00192    * Sync object for fair locks
00193    */
00194   final class FairSync : Sync {
00195     final void lock() { 
00196       acquire(1); 
00197     }
00198 
00199     /*
00200      * Fair version of tryAcquire.  Don't grant access unless
00201      * recursive call or no waiters or is first.
00202      */
00203     protected final bool tryAcquire(int acquires) { 
00204       Thread current = Thread.getThis();
00205       int c = state;
00206       if (c == 0) {
00207         Thread first = getFirstQueuedThread();
00208         if ((first is null || first is current) && 
00209             Atomic.compareAndSet32(&state_, c, acquires)) {
00210           owner = current;
00211           return true;
00212         }
00213       }
00214       else if (current is owner) {
00215         state = c+acquires;
00216         return true;
00217       }
00218       return false;
00219     }
00220   }
00221 
00227   this(bool fair = false) { 
00228     if (fair)
00229       sync = new FairSync();
00230     else
00231       sync = new NonfairSync();
00232   }
00233 
00248   void lock() {
00249     sync.lock();
00250   }
00251 
00275   bool tryLock() {
00276     return sync.nonfairTryAcquire(1);
00277   }
00278 
00321   bool tryLock(long timeout, TimeUnit unit) {
00322     return sync.tryAcquireNanos(1, toNanos(timeout,unit));
00323   }
00324 
00332   void unlock() {
00333     sync.release(1);
00334   }
00335 
00356   Condition newCondition() {
00357     return sync.newCondition();
00358   }
00359 
00393   int getHoldCount() {
00394     return sync.getHoldCount();
00395   }
00396 
00404   bool isHeldByCurrentThread() {
00405     return sync.isHeldExclusively();
00406   }
00407 
00415   bool isLocked() {
00416     return sync.isLocked();
00417   }
00418 
00423   final bool isFair() {
00424     return cast(FairSync)sync !is null;
00425   }
00426 
00436   protected Thread getOwner() {
00437     return sync.getOwner();
00438   }
00439 
00450   final bool hasQueuedThreads() { 
00451     return sync.hasQueuedThreads();
00452   }
00453 
00454 
00465   final bool hasQueuedThread(Thread thread) { 
00466     return sync.isQueued(thread);
00467   }
00468 
00469 
00479   final int getQueueLength() {
00480     return sync.getQueueLength();
00481   }
00482 
00493   protected Thread[] getQueuedThreads() {
00494     return sync.getQueuedThreads();
00495   }
00496 
00507   bool hasWaiters(Condition condition) {
00508     if ((condition is null) || 
00509         (cast(AbstractLock.ConditionObject)condition is null))
00510       throw new IllegalArgumentException();
00511     return sync.hasWaiters(cast(AbstractLock.ConditionObject)condition);
00512   }
00513 
00524   int getWaitQueueLength(Condition condition) {
00525     if ((condition is null) || 
00526         (cast(AbstractLock.ConditionObject)condition is null))
00527       throw new IllegalArgumentException();
00528     return sync.getWaitQueueLength(cast(AbstractLock.ConditionObject)condition);
00529   }
00530 
00543   protected Thread[] getWaitingThreads(Condition condition) {
00544     if ((condition is null) || 
00545         (cast(AbstractLock.ConditionObject)condition is null))
00546       throw new IllegalArgumentException();
00547     return sync.getWaitingThreads(cast(AbstractLock.ConditionObject)condition);
00548   }
00549 
00557   char[] toString() {
00558     Thread owner = sync.getOwner();
00559     return super.toString() ~ ((owner is null) ?
00560                                "[Unlocked]" :
00561                                ("[Locked by thread" ~ owner.toString() ~ "]"));
00562   }
00563 
00564   unittest {
00565     ReentrantLock lock;
00566     int acquired;
00567     Thread[] t;
00568     
00569     ThreadReturn f() {
00570       int n;
00571       Thread tt = Thread.getThis();
00572       for (n=0; n < t.length; n++) {
00573         if (tt is t[n])
00574           break;
00575       }
00576       version (LocksVerboseUnittest)
00577         printf(" thread %d started\n",n);
00578       lock.lock();
00579       version (LocksVerboseUnittest)
00580         printf(" thread %d aquired\n",n);
00581       for (int k=0;k<1000;k++)
00582         Thread.yield();
00583       lock.unlock();
00584       acquired++;
00585       version (LocksVerboseUnittest)
00586         printf(" thread %d released\n",n);
00587       return 0;
00588     }
00589 
00590     lock = new ReentrantLock;
00591     acquired = 0;
00592     t = new Thread[3];
00593     int n;
00594     for (n=0; n<t.length; n++) {
00595       t[n] = new Thread(&f);
00596     }
00597     version (LocksVerboseUnittest)
00598       printf("starting locks.reentrantlock unittest\n");
00599     for (n=0; n<t.length; n++) {
00600       t[n].start();
00601     }
00602     while (acquired != n)
00603       Thread.yield();
00604 
00605     
00606     // test ScopedLock
00607     {
00608       auto ScopedLock sl = new ScopedLock(lock);
00609       assert( lock.isHeldByCurrentThread );
00610       
00611     }
00612     assert( ~lock.isHeldByCurrentThread );
00613 
00614     version (LocksVerboseUnittest)
00615       printf("finished locks.reentrantlock unittest\n");
00616   }
00617 }

Generated on Mon Nov 14 10:59:40 2005 for Mango by  doxygen 1.4.0