Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

MultiReadWriteLock.h

Go to the documentation of this file.
00001 /*  ReadWriteLock.h - N readers, 1 writer problem for multiple processes
00002 
00003     Copyright (C) 2001 Mark Weaver
00004     Written by Mark Weaver <mark@npsl.co.uk>
00005 
00006     Part of the Open-Win32 library.
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public
00018     License along with this library; if not, write to the
00019     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020     Boston, MA  02111-1307, USA.
00021 */
00022 
00027 #ifndef OW32_MultiReadWriteLock_h
00028 #define OW32_MultiReadWriteLock_h
00029 
00030 #include <OW32/SyncObjects.h>
00031 #include <rpc.h>
00032 
00033 namespace OW32
00034 {
00035 
00039 class OW32_LIB_EXPORT CMultiReadWriteLock
00040 {
00041 private:
00042     struct LOCKDATA
00043     {
00044         int m_readers, m_pending_readers;
00045         int m_writers, m_pending_writers;
00046     };
00047 
00048     CMutex* m_mtxReadWriteFlags;
00049     LOCKDATA* m_pLockData;
00050     CEvent* m_evReadDone, *m_evWriteDone;
00051     TCHAR m_lockName[128];
00052 
00053 public:
00054     CMultiReadWriteLock(LPCTSTR lockName = NULL)
00055     {
00056         if (lockName == NULL) {
00057 #if 0
00058             UUID uuid;
00059             UuidCreate(&uuid);
00060             _stprintf(m_lockName, _T("Global\\%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X"), 
00061                 uuid.Data1, uuid.Data2, uuid.Data3, uuid.Data4[0], uuid.Data4[1], 
00062                 uuid.Data4[2], uuid.Data4[3], uuid.Data4[4], uuid.Data4[5], 
00063                 uuid.Data4[6], uuid.Data4[7]);
00064 #endif
00065         } else {
00066             _tcsncpy(m_lockName, lockName, 128);
00067             m_lockName[127] = _T('\0');
00068         }
00069         CreateLockData();
00070     }
00071 
00072     ~CMultiReadWriteLock()
00073     {
00074         if (m_pLockData) {
00075             UnmapViewOfFile(m_pLockData);
00076         }
00077         delete m_evReadDone;
00078         delete m_evWriteDone;
00079         delete m_mtxReadWriteFlags;
00080     }
00081 
00082 private:
00083     void CreateLockData()
00084     {
00085         TCHAR lockName[128+32];
00086 
00087         _tcscpy(lockName, m_lockName);
00088         _tcscat(lockName, _T(".mmf"));
00089         XHANDLE hMMF = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, lockName);
00090         if (!hMMF) {
00091             hMMF = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
00092                                      0, sizeof(LOCKDATA), lockName);
00093         }
00094         m_pLockData = (LOCKDATA*)MapViewOfFile(hMMF, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LOCKDATA));
00095         m_pLockData->m_readers = m_pLockData->m_pending_readers = 0;
00096         m_pLockData->m_writers = m_pLockData->m_pending_writers = 0;
00097         _tcscpy(lockName, m_lockName);
00098         _tcscat(lockName, _T(".readDone"));
00099         m_evReadDone = new CEvent(TRUE,FALSE,lockName);
00100         _tcscpy(lockName, m_lockName);
00101         _tcscat(lockName, _T(".writeDone"));
00102         m_evWriteDone = new CEvent(TRUE,FALSE,lockName);
00103         _tcscpy(lockName, m_lockName);
00104         _tcscat(lockName, _T(".flags"));
00105         m_mtxReadWriteFlags = new CMutex(FALSE,lockName);
00106     }
00107 
00108 public:
00109     BOOL ReadLock(DWORD dwTimeout=INFINITE)
00110     {
00111         DWORD dwStart = GetTickCount();
00112         int pend_increment=1;
00113         while (dwTimeout == INFINITE || (GetTickCount() - dwStart < dwTimeout)) {
00114             {
00115                 CSingleLock lock(*m_mtxReadWriteFlags);
00116                 m_pLockData->m_pending_readers += pend_increment;
00117                 pend_increment = 0;
00118                 if (m_pLockData->m_writers==0) {
00119                     m_evReadDone->Reset(); // clear read done signal
00120                     ++m_pLockData->m_readers;
00121                     --m_pLockData->m_pending_readers;
00122                     return TRUE;
00123                 }
00124             }
00125             m_evWriteDone->Lock(); // wait for `write complete' signal
00126         }
00127         if (pend_increment == 0) {
00128             CSingleLock lock(*m_mtxReadWriteFlags);
00129             m_pLockData->m_pending_readers--;
00130         }
00131         return FALSE;
00132     }
00133 
00134     void ReadUnlock()
00135     {
00136         CSingleLock lock(*m_mtxReadWriteFlags);
00137         --m_pLockData->m_readers;
00138         if (m_pLockData->m_readers == 0 && m_pLockData->m_pending_writers > 0)
00139             m_evReadDone->Set();
00140     }
00141 
00142     BOOL WriteLock(DWORD dwTimeout=INFINITE)
00143     {
00144         DWORD dwStart = GetTickCount();
00145         int pend_increment=1;
00146         while (dwTimeout == INFINITE || (GetTickCount() - dwStart < dwTimeout)) {
00147             bool havereaders=0;
00148             {
00149                 CSingleLock lock(*m_mtxReadWriteFlags);
00150                 m_pLockData->m_pending_writers += pend_increment;
00151                 pend_increment = 0;
00152                 if (m_pLockData->m_readers==0 && m_pLockData->m_writers==0) {
00153                     m_evWriteDone->Reset(); // clear write done signal
00154                     --m_pLockData->m_pending_writers;
00155                     ++m_pLockData->m_writers;
00156                     return TRUE;
00157                 }
00158                 havereaders = (m_pLockData->m_readers>0);
00159             }
00160             if (havereaders)
00161                 m_evReadDone->Lock();
00162             else
00163                 m_evWriteDone->Lock();
00164         }
00165         if (pend_increment == 0) {
00166             CSingleLock lock(*m_mtxReadWriteFlags);
00167             --m_pLockData->m_pending_writers;
00168         }
00169         return FALSE;
00170     }
00171 
00172     virtual void WriteUnlock()
00173     {
00174         CSingleLock lock(*m_mtxReadWriteFlags);
00175         --m_pLockData->m_writers;
00176         if (m_pLockData->m_pending_readers != 0 || m_pLockData->m_pending_writers != 0)
00177             m_evWriteDone->Set();
00178     }
00179 
00180 private:
00181     class CReadLock : public CSyncObject
00182     {
00183         virtual BOOL Lock(DWORD dwTimeout)
00184         {
00185             CMultiReadWriteLock& parent = 
00186                 *(CMultiReadWriteLock *)((const char *)this-offsetof(CMultiReadWriteLock,m_ReadLock));
00187             return parent.ReadLock(dwTimeout);
00188         }
00189 
00190         virtual void Unlock()
00191         {
00192             CMultiReadWriteLock& parent = 
00193                 *(CMultiReadWriteLock *)((const char *)this-offsetof(CMultiReadWriteLock,m_ReadLock));
00194             parent.ReadUnlock();
00195         }
00196     };
00197     friend CReadLock;
00198 
00199     class CWriteLock : public CSyncObject
00200     {
00201         virtual BOOL Lock(DWORD dwTimeout)
00202         {
00203             CMultiReadWriteLock& parent = 
00204                 *(CMultiReadWriteLock *)((const char *)this-offsetof(CMultiReadWriteLock,m_WriteLock));
00205             return parent.WriteLock(dwTimeout);
00206         }
00207 
00208         virtual void Unlock()
00209         {
00210             CMultiReadWriteLock& parent = 
00211                 *(CMultiReadWriteLock *)((const char *)this-offsetof(CMultiReadWriteLock,m_WriteLock));
00212             parent.WriteUnlock();
00213         }
00214     };
00215     friend CWriteLock;
00216 
00217 public:
00218     CWriteLock& GetWriteLock() { return m_WriteLock; }
00219     CReadLock& GetReadLock() { return m_ReadLock; }
00220 
00221 private:
00222     CReadLock m_ReadLock;
00223     CWriteLock m_WriteLock;
00224 };
00225 
00226 } // namespace OW32
00227 
00228 #endif // OW32_MultiReadWriteLock_h

Generated on Sun Jun 5 01:29:17 2005 for OW32 by  doxygen 1.3.9.1