MicoleBusWriteLock.h

Go to the documentation of this file.
00001 /*
00002  * This file is part of Micole Architecture
00003  *
00004  * Copyright (C) 2007 Micole partners
00005  *
00006  * Micole Architecture is free software: you can redistribute it 
00007  * and/or modify it under the terms of the GNU Lesser General 
00008  * Public License as published by the Free Software Foundation, 
00009  * either version 3 of the License, or (at your option) any 
00010  * later version.
00011  *
00012  * Micole Architecture is distributed in the hope that it will be 
00013  * useful, * but WITHOUT ANY WARRANTY; without even the implied 
00014  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
00015  * PURPOSE.  See the GNU Lesser General Public License for more 
00016  * details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with Micole Architecture.  If not, see
00020  * <http://www.gnu.org/licenses/>.
00021  */
00022 
00023 #ifndef READWRITELOCK_H_INCLUDED
00024 #define READWRITELOCK_H_INCLUDED
00025 
00026 #pragma once
00027 
00028 #include "stdafx.h"
00029 #include "windows.h"
00030 
00036 // MicoleBusReadWriteLock is a read/write mutex.
00037 //
00038 // Any number of readers can acquire the mutex for read (LockRead()).
00039 // Only single writer can acquire the mutex for write (LockWrite()).
00040 // No other writers or readers can hold the mutex while writer uses it.
00041 //
00042 // MicoleBusReadWriteLock does not prefer neither writers nor readers.
00043 // I.e. if both writers and readers are waiting for the lock,
00044 // any of them can grab the lock when it is released by previous owner.
00045 //
00046 // MicoleBusReadWriteLock is recursive, but not upgradable. This means that
00047 //
00048 // if you have a read lock, you can safely acquire another read lock.
00049 // if you have a read lock, you CANNOT acquire a write lock (deadlock!).
00050 //
00051 // if you have a write lock, you can safely acquire another write lock.
00052 // if you have a write lock, you CANNOT acquire a read lock (deadlock!).
00053 //
00054 class MicoleBusReadWriteLock
00055 {
00056     CMutex m_Access;
00057     int    m_Readers;
00058     CMutex m_WriterMutex;
00059     CEvent m_CanRead;
00060     CEvent m_CanWrite;
00061 
00062     MicoleBusReadWriteLock( MicoleBusReadWriteLock const& ); // not implemented
00063     void operator=( MicoleBusReadWriteLock const& ); // not implemented
00064 
00065 public:
00066     MicoleBusReadWriteLock();
00067     
00068     bool LockRead( DWORD Timeout = INFINITE );
00069     bool LockWrite( DWORD Timeout = INFINITE );
00070     bool UnlockRead( DWORD Timeout = INFINITE );
00071     bool UnlockWrite( DWORD Timeout = INFINITE );
00072 };
00073 
00074 
00075 #pragma warning( disable: 4786 )
00076 #include <map>
00077 
00078 // MicoleBusReadWriteLockEx is more sofisticated read/write mutex.
00079 // It is recursive and upgradable.
00080 //
00081 // That is, a thread can acquire and release read and write locks in arbitrary order
00082 // The only rule is that every successfully acquired lock must be eventually released
00083 //
00084 // E.g. LockRead(), LockWrite(), UnlockRead(), UnlockWrite() is allowed sequence.
00085 //
00086 //
00087 // MicoleBusReadWriteLockEx prefers writers over readers. E.g., when a writer
00088 // is waiting for the lock, no new readers can acquire the lock. Existing
00089 // readers may continue to use the lock. This policy prevents so-called
00090 // "writer starvation" when writers never get access to the lock because of
00091 // too much readers.
00092 //
00093 class MicoleBusReadWriteLockEx
00094 {
00095     struct KThreadInfo
00096     {
00097         int ReadCount;
00098         int WriteCount;
00099 
00100         bool IsReader() { return ReadCount > 0; };
00101         bool IsWriter() { return WriteCount > 0; };
00102     };
00103 
00104     typedef std::map<DWORD, KThreadInfo> KThreadMap;
00105     KThreadMap m_Threads;
00106 
00107     // Number of reader threads; 
00108     // Note: writer threads are not reader threads, even if they have read locks
00109     int m_TotalReaderThreads; 
00110     int m_TotalWriterThreads; // current writer + waiting writers
00111 
00112     CMutex m_Access;
00113     CMutex m_WriterMutex;
00114     CEvent m_CanRead;
00115     CEvent m_CanWrite;
00116 
00117     void IncReaders()
00118         {
00119             ++m_TotalReaderThreads;
00120             ResetEvent(m_CanWrite);
00121         };
00122 
00123     void DecReaders()
00124         {
00125             if (--m_TotalReaderThreads == 0)
00126                 SetEvent(m_CanWrite);
00127         };
00128 
00129     void IncWriters()
00130         {
00131             ++m_TotalWriterThreads;
00132             ResetEvent(m_CanRead);
00133         };
00134 
00135     void DecWriters()
00136         {
00137             if (--m_TotalWriterThreads == 0)
00138                 SetEvent(m_CanRead);
00139         };
00140 
00141     MicoleBusReadWriteLockEx( MicoleBusReadWriteLockEx const& ); // not implemented
00142     void operator=( MicoleBusReadWriteLockEx const& ); // not implemented
00143 
00144 public:
00145     MicoleBusReadWriteLockEx();
00146     
00147     bool LockRead( DWORD Timeout = INFINITE );
00148     bool LockWrite( DWORD Timeout = INFINITE );
00149     bool UnlockRead( DWORD Timeout = INFINITE );
00150     bool UnlockWrite( DWORD Timeout = INFINITE );
00151 
00152 };
00153 
00154 // Template class below automatically acquires a read lock in constructor
00155 // and releases it in destructor. It is similar to MFC's CSingleLock class.
00156 // NOTE: unlike CSingleLock, KReadLockTempl will lock the resource by default
00157 // (bInitialLock parameter defaults to true).
00158 //
00159 template <class T>
00160 class KReadLockTempl
00161 {
00162     bool m_bLocked;
00163     T&   m_Lock;
00164 
00165     KReadLockTempl( KReadLockTempl const& ); // not implemented
00166     void operator=( KReadLockTempl const& ); // not implemented
00167 
00168 
00169 public:
00170     KReadLockTempl(T& Lock, bool bInitialLock = true)
00171         :
00172         m_Lock(Lock),
00173         m_bLocked(false)
00174         {
00175             if (bInitialLock)
00176             {
00177                 VERIFY(m_Lock.LockRead());
00178                 m_bLocked = true;
00179             }
00180         };
00181 
00182     ~KReadLockTempl()
00183         {
00184             if (m_bLocked)
00185                 VERIFY(m_Lock.UnlockRead());
00186         };
00187 
00188     bool Lock(DWORD Timeout = INFINITE)
00189         {
00190             ASSERT(!m_bLocked);
00191             m_bLocked = m_Lock.LockRead(Timeout);
00192             return m_bLocked;
00193         };
00194 
00195     bool Unlock(DWORD Timeout = INFINITE)
00196         {
00197             ASSERT(m_bLocked);
00198             m_bLocked = !m_Lock.UnlockRead(Timeout);
00199             return !m_bLocked;
00200         }
00201 };
00202 
00203 // Template class below automatically acquires a write lock in constructor
00204 // and releases it in destructor. It is similar to MFC's CSingleLock class.
00205 // NOTE: unlike CSingleLock, KWriteLockTempl will lock the resource by default
00206 // (bInitialLock parameter defaults to true).
00207 //
00208 template <class T>
00209 class KWriteLockTempl
00210 {
00211     bool m_bLocked;
00212     T&   m_Lock;
00213 
00214     KWriteLockTempl( KWriteLockTempl const& ); // not implemented
00215     void operator=( KWriteLockTempl const& ); // not implemented
00216 
00217 
00218 public:
00219     KWriteLockTempl(T& Lock, bool bInitialLock = true)
00220         :
00221         m_Lock(Lock),
00222         m_bLocked(false)
00223         {
00224             if (bInitialLock)
00225             {
00226                 VERIFY(m_Lock.LockWrite());
00227                 m_bLocked = true;
00228             }
00229         };
00230 
00231     ~KWriteLockTempl()
00232         {
00233             if (m_bLocked)
00234                 VERIFY(m_Lock.UnlockWrite());
00235         };
00236 
00237     bool Lock(DWORD Timeout = INFINITE)
00238         {
00239             ASSERT(!m_bLocked);
00240             m_bLocked = m_Lock.LockWrite(Timeout);
00241             return m_bLocked;
00242         };
00243 
00244     bool Unlock(DWORD Timeout = INFINITE)
00245         {
00246             ASSERT(m_bLocked);
00247             m_bLocked = !m_Lock.UnlockWrite(Timeout);
00248             return !m_bLocked;
00249         }
00250 };
00251 
00252 typedef KReadLockTempl<MicoleBusReadWriteLock> KReadLock;
00253 typedef KWriteLockTempl<MicoleBusReadWriteLock> KWriteLock;
00254 typedef KReadLockTempl<MicoleBusReadWriteLockEx> KReadLockEx;
00255 typedef KWriteLockTempl<MicoleBusReadWriteLockEx> KWriteLockEx;
00256 
00257 
00258 #endif //READWRITELOCK_H_INCLUDED

Generated on Tue Oct 16 17:10:43 2007 for Micole by  doxygen 1.4.7