00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef __RW_LOCK__H__
00013 #define __RW_LOCK__H__
00014
00015 #include <wx/thread.h>
00016 #include <list>
00017 #include "flexilog.h"
00018
00019 namespace VRUT
00020 {
00022 class ReadWriteMutex
00023 {
00024 public:
00026 static const unsigned MAX_READERS = 32;
00027
00029 ReadWriteMutex() : semaphore(MAX_READERS, MAX_READERS)
00030 {
00031 writer.recursiveLocks = 0;
00032 writer.threadID = 0;
00033 }
00034
00035 private:
00037 struct LockOwner
00038 {
00040 wxThreadIdType threadID;
00042 unsigned recursiveLocks;
00043 };
00044 typedef std::list<LockOwner> LockOwnerList;
00045
00047 mutable wxMutex mutex;
00049 wxMutex semMutex;
00051 mutable wxSemaphore semaphore;
00053 mutable LockOwnerList readers;
00055 LockOwner writer;
00056
00058 LockOwnerList::iterator getCurrentReader() const
00059 {
00060 wxThreadIdType threadID = wxThread::GetCurrentId();
00061 for (LockOwnerList::iterator it = readers.begin(); it != readers.end(); it++)
00062 if (it->threadID == threadID)
00063 return it;
00064 return readers.end();
00065 }
00066
00067 public:
00069 bool IsOk() const
00070 {
00071 return mutex.IsOk() && semMutex.IsOk();
00072 }
00073
00075 void ReadLock() const
00076 {
00077 mutex.Lock();
00079 wxThreadIdType threadID = wxThread::GetCurrentId();
00080 LockOwnerList::iterator ourReader = getCurrentReader();
00081 if (ourReader != readers.end())
00082 ourReader->recursiveLocks++;
00083 else
00084 {
00085 LockOwner lo = { threadID, 1 };
00086 readers.push_back(lo);
00088 if (writer.recursiveLocks == 0 || writer.threadID != threadID)
00089 {
00090 mutex.Unlock();
00091 semaphore.Wait();
00092 return;
00093 }
00094 }
00095 mutex.Unlock();
00096 }
00097
00099 void ReadUnlock() const
00100 {
00101 wxMutexLocker lock(mutex);
00102 LockOwnerList::iterator ourReader = getCurrentReader();
00103 if (ourReader != readers.end())
00104 {
00105 if (--ourReader->recursiveLocks == 0)
00106 {
00107 readers.erase(ourReader);
00108 semaphore.Post();
00109 }
00110 }
00111 else
00112 LOGERROR(wxT("<ReadWriteMutex>Read unlock called with no matching previous read lock"));
00113 }
00114
00116 void WriteLock()
00117 {
00118 mutex.Lock();
00119
00121 wxThreadIdType threadID = wxThread::GetCurrentId();
00122 if (writer.recursiveLocks && writer.threadID == threadID)
00123 writer.recursiveLocks++;
00124 else
00125 {
00126 mutex.Unlock();
00127 wxMutexLocker semLock(semMutex);
00128 for (unsigned i = 0; i < MAX_READERS; i++)
00129 semaphore.Wait();
00130 mutex.Lock();
00131 wxASSERT_MSG(writer.threadID == 0, wxT("<ReadWriteMutex>Write lock was not unlocked properly"));
00132 writer.threadID = threadID;
00133 writer.recursiveLocks = 1;
00134 }
00135 mutex.Unlock();
00136 }
00137
00139 void WriteUnlock()
00140 {
00141 wxMutexLocker lock(mutex);
00142 wxThreadIdType threadID = wxThread::GetCurrentId();
00143 wxASSERT_MSG(writer.threadID == threadID, wxT("<ReadWriteMutex>Unlocking write lock locked by different thread"));
00144 if (--writer.recursiveLocks == 0)
00145 {
00146 for (unsigned i = 0; i < MAX_READERS; i++)
00147 semaphore.Post();
00148 writer.threadID = 0;
00149 }
00150 }
00151 };
00152
00153
00155 class ReadLocker
00156 {
00157 public:
00159 ReadLocker(const ReadWriteMutex & rwLock) : m_rwLock(rwLock)
00160 {
00161 m_rwLock.ReadLock();
00162 }
00163
00165 ~ReadLocker()
00166 {
00167 m_rwLock.ReadUnlock();
00168 }
00169
00170 private:
00172 const ReadWriteMutex & m_rwLock;
00173 };
00174
00175
00177 class WriteLocker
00178 {
00179 public:
00181 WriteLocker(ReadWriteMutex& rwLock) : m_rwLock(rwLock)
00182 {
00183 m_rwLock.WriteLock();
00184 }
00185
00187 ~WriteLocker()
00188 {
00189 m_rwLock.WriteUnlock();
00190 }
00191
00192 private:
00194 ReadWriteMutex& m_rwLock;
00195 };
00196 };
00197
00198 #endif