00001 00009 #ifndef ATOMS_RWMUTEX_HH 00010 #define ATOMS_RWMUTEX_HH 00011 00012 #include <atoms/gen.hh> 00013 #include <pthread.h> 00014 #ifndef PTHREAD_RWLOCK_INITIALIZER 00015 #include <boost/static_assert.hpp> 00016 #include <boost/integer_traits.hpp> 00017 #include <atoms/mutex.hh> 00018 #include <atoms/thread.hh> // for Condition 00019 #endif 00020 00021 namespace atoms { 00022 00030 class RWMutex : boost::noncopyable { 00031 public: 00032 RWMutex() : 00033 #ifdef PTHREAD_RWLOCK_INITIALIZER 00034 me(PTHREAD_RWLOCK_INITIALIZER) 00035 #else 00036 active(0), numBlockedWriters(0) 00037 #endif 00038 {} 00039 00040 class ReadMon : public Monitor { 00041 public: 00042 ReadMon(RWMutex &m); 00043 ~ReadMon(); 00044 private: 00045 RWMutex &m; 00046 }; 00047 00048 class WriteMon : public Monitor { 00049 public: 00050 WriteMon(RWMutex &m); 00051 ~WriteMon(); 00052 private: 00053 RWMutex &m; 00054 }; 00055 private: 00056 #ifdef PTHREAD_RWLOCK_INITIALIZER 00057 pthread_rwlock_t me; 00058 #else 00059 const static unsigned short MAX_ACTIVE_READERS = 16; 00060 Mutex m; 00061 unsigned short active; 00062 unsigned short numBlockedWriters; 00063 Condition writerCondition; 00064 Condition readerCondition; 00065 #endif 00066 }; 00067 00068 #ifdef PTHREAD_RWLOCK_INITIALIZER 00069 RWMutex::ReadMon::ReadMon(RWMutex &m) : m(m) { 00070 int retval = pthread_rwlock_rdlock(&mm.me); 00071 assert(retval == 0); 00072 } 00073 00074 RWMutex::ReadMon::~ReadMon() { 00075 int retval = pthread_rwlock_unlock(&mm.me); 00076 assert(retval == 0); 00077 } 00078 00079 RWMutex::WriteMon::WriteMon(RWMutex &m) : m(m) { 00080 int retval = pthread_rwlock_wrlock(&&m.me); 00081 assert(retval == 0); 00082 } 00083 00084 RWMutex::WriteMon::~WriteMon() { 00085 int retval = pthread_rwlock_unlock(&mm.me); 00086 assert(retval == 0); 00087 } 00088 #else 00089 inline RWMutex::ReadMon::ReadMon(RWMutex &m) : m(m) { 00090 Mutex::Mon mm(m.m); 00091 while (m.active == MAX_ACTIVE_READERS || m.numBlockedWriters > 0) { 00092 m.readerCondition.wait(mm); 00093 } 00094 m.active++; 00095 } 00096 00097 inline RWMutex::ReadMon::~ReadMon() { 00098 Mutex::Mon mm(m.m); 00099 assert(m.active > 0); 00100 if (m.numBlockedWriters > 0) { 00101 m.writerCondition.signal(); 00102 } else if (m.active-- == MAX_ACTIVE_READERS) { 00103 m.readerCondition.signal(); 00104 } 00105 } 00106 00107 inline RWMutex::WriteMon::WriteMon(RWMutex &m) : m(m) { 00108 Mutex::Mon mm(m.m); 00109 while (m.active > 0) { 00110 if (++m.numBlockedWriters == 0) { 00111 // Wrapped; too many writers. 00112 abort(); 00113 } 00114 try { 00115 m.writerCondition.wait(mm); 00116 } catch (...) { 00117 if (--m.numBlockedWriters == 0) { 00118 m.readerCondition.broadcast(); 00119 } 00120 throw; 00121 } 00122 m.numBlockedWriters--; 00123 } 00124 m.active = MAX_ACTIVE_READERS; 00125 } 00126 00127 inline RWMutex::WriteMon::~WriteMon() { 00128 Mutex::Mon mm(m.m); 00129 assert(m.active == MAX_ACTIVE_READERS); 00130 m.active = 0; 00131 if (m.numBlockedWriters > 0) { 00132 m.writerCondition.signal(); 00133 } else { 00134 m.readerCondition.broadcast(); 00135 } 00136 } 00137 #endif 00138 00139 } // namespace atoms 00140 00141 #endif // !ATOMS_RWMUTEX_HH
1.3.5