00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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();
00120 ++m_pLockData->m_readers;
00121 --m_pLockData->m_pending_readers;
00122 return TRUE;
00123 }
00124 }
00125 m_evWriteDone->Lock();
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();
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 }
00227
00228 #endif // OW32_MultiReadWriteLock_h