Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

ReadersWritersLock.hpp

Go to the documentation of this file.
00001 /*==========================================================================
00002  * Copyright (c) 2004 University of Massachusetts.  All Rights Reserved.
00003  *
00004  * Use of the Lemur Toolkit for Language Modeling and Information Retrieval
00005  * is subject to the terms of the software license set forth in the LICENSE
00006  * file included with this software, and also available at
00007  * http://www.lemurproject.org/license.html
00008  *
00009  *==========================================================================
00010  */
00011 
00012 //
00013 // ReadersWritersLock
00014 //
00015 // 14 December 2004 -- tds
00016 //
00017 
00018 #include "indri/ScopedMonitor.hpp"
00019 #include "indri/ConditionVariable.hpp"
00020 
00021 #ifndef INDRI_READERSWRITERSLOCK_HPP
00022 #define INDRI_READERSWRITERSLOCK_HPP
00023 namespace indri
00024 {
00025   namespace thread
00026   {
00027     
00028     class ReadersWritersLock {
00029     private:
00030       struct wait_queue_entry {
00031         bool writing;
00032         bool awakened;
00033         wait_queue_entry* next;
00034         ConditionVariable wakeup;
00035       };
00036 
00037       Mutex _mutex;
00038       wait_queue_entry* _head;
00039       wait_queue_entry* _tail;
00040 
00041       int _readers;
00042       int _writers;
00043 
00044       void _enqueue( wait_queue_entry& entry ) {
00045         entry.awakened = false;
00046 
00047         // called within the mutex
00048         if( _tail == 0 ) {
00049           entry.next = 0;
00050           _tail = &entry;
00051           _head = &entry;
00052         } else {
00053           entry.next = 0;
00054           _tail->next = &entry;
00055           _tail = &entry;
00056         }
00057       }
00058 
00059       void _wakeOthers() {
00060         bool reading = false;
00061 
00062         if( _head ) {
00063           // wakeup the next thread, no matter what
00064           _head->awakened = true;
00065           _head->wakeup.notifyOne();
00066           reading = !_head->writing;
00067           _head = _head->next;
00068 
00069           // if the next waiter wants to read, then we should
00070           // continue to wake threads up until there are no readers left
00071           if( reading ) {
00072             while( _head && _head->writing == false ) {
00073               _head->awakened = true;
00074               _head->wakeup.notifyOne();
00075               _head = _head->next;
00076             }
00077           }
00078         }
00079 
00080         // if we took the last thing off the queue, fix up the tail
00081         if( _head == 0 ) {
00082           _tail = 0;
00083         }
00084       }
00085 
00086     public:
00087       ReadersWritersLock() :
00088         _tail(0),
00089         _head(0),
00090         _readers(0),
00091         _writers(0)
00092       {
00093       }
00094 
00095       void lockRead() {
00096         _mutex.lock();
00097 
00098         if( _head != 0 || _writers ) {
00099           do {
00100             wait_queue_entry entry;
00101 
00102             entry.writing = false;
00103             entry.next = 0;
00104 
00105             _enqueue( entry );
00106 
00107             // wait for our time to come
00108             entry.wakeup.wait( _mutex );
00109           }
00110           while( _writers );
00111         }
00112         _readers++;
00113         assert( !_writers );
00114 
00115         _mutex.unlock();
00116       }
00117     
00118       void lockWrite() {
00119         _mutex.lock();
00120 
00121         if( _head != 0 || _readers || _writers ) {
00122           do {
00123             wait_queue_entry entry;
00124 
00125             entry.writing = true;
00126             entry.next = 0;
00127 
00128             _enqueue( entry );
00129 
00130             // wait for our time to come
00131             entry.wakeup.wait( _mutex );
00132           } 
00133           while( _readers || _writers );
00134         }
00135 
00136         assert( _writers == 0 );
00137         _writers++;
00138         _mutex.unlock();
00139 
00140         assert( !_readers && _writers == 1 );
00141       }
00142 
00143       void unlockWrite() {
00144         assert( _writers );
00145         assert( !_readers );
00146 
00147         _mutex.lock();
00148         _writers = 0;
00149         _wakeOthers();
00150         _mutex.unlock();
00151       }
00152 
00153       void unlockRead() {
00154         assert( _readers );
00155         assert( !_writers );
00156 
00157         _mutex.lock();
00158         _readers--;
00159 
00160         if( _readers == 0 )
00161           _wakeOthers();
00162 
00163         _mutex.unlock();
00164       }
00165 
00166       void yieldWrite() {
00167         assert( !_readers && _writers == 1 );
00168 
00169         if( _head ) {
00170           unlockWrite();
00171           lockWrite();
00172         }
00173 
00174         assert( !_readers && _writers == 1 );
00175       }
00176 
00177       void yieldRead() {
00178         assert( _readers && _writers == 0 );
00179 
00180         if( _head ) {
00181           unlockRead();
00182           lockRead();
00183         }
00184 
00185         assert( _readers && _writers == 0 );
00186       }
00187 
00188     };
00189   }
00190 }
00191 
00192 #endif // INDRI_READERSWRITERSLOCK_HPP
00193 

Generated on Tue Jun 15 11:02:55 2010 for Lemur by doxygen 1.3.4