Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef __SINGLE_PRODUCER_CONSUMER_H
00010 #define __SINGLE_PRODUCER_CONSUMER_H
00011
00012 #include "RakAssert.h"
00013
00014 static const int MINIMUM_LIST_SIZE=8;
00015
00016 #include "RakMemoryOverride.h"
00017 #include "Export.h"
00018
00021 namespace DataStructures
00022 {
00024 template <class SingleProducerConsumerType>
00025 class RAK_DLL_EXPORT SingleProducerConsumer
00026 {
00027 public:
00028
00029 SingleProducerConsumer();
00030
00031
00032 ~SingleProducerConsumer();
00033
00036 SingleProducerConsumerType* WriteLock(void);
00037
00041 void CancelWriteLock(SingleProducerConsumerType* cancelToLocation);
00042
00044 void WriteUnlock(void);
00045
00049 SingleProducerConsumerType* ReadLock(void);
00050
00051
00053 void CancelReadLock(SingleProducerConsumerType* cancelToLocation);
00054
00057 void ReadUnlock(void);
00058
00060 void Clear(void);
00061
00064 int Size(void) const;
00065
00068 bool CheckReadUnlockOrder(const SingleProducerConsumerType* data) const;
00069
00072 bool ReadIsLocked(void) const;
00073
00074 private:
00075 struct DataPlusPtr
00076 {
00077 DataPlusPtr () {readyToRead=false;}
00078 SingleProducerConsumerType object;
00079
00080
00081 volatile bool readyToRead;
00082 volatile DataPlusPtr *next;
00083 };
00084 volatile DataPlusPtr *readAheadPointer;
00085 volatile DataPlusPtr *writeAheadPointer;
00086 volatile DataPlusPtr *readPointer;
00087 volatile DataPlusPtr *writePointer;
00088 unsigned readCount, writeCount;
00089 };
00090
00091 template <class SingleProducerConsumerType>
00092 SingleProducerConsumer<SingleProducerConsumerType>::SingleProducerConsumer()
00093 {
00094
00095 readPointer = RakNet::OP_NEW<DataPlusPtr>( __FILE__, __LINE__ );
00096 writePointer=readPointer;
00097 readPointer->next = RakNet::OP_NEW<DataPlusPtr>( __FILE__, __LINE__ );
00098 int listSize;
00099 #ifdef _DEBUG
00100 RakAssert(MINIMUM_LIST_SIZE>=3);
00101 #endif
00102 for (listSize=2; listSize < MINIMUM_LIST_SIZE; listSize++)
00103 {
00104 readPointer=readPointer->next;
00105 readPointer->next = RakNet::OP_NEW<DataPlusPtr>( __FILE__, __LINE__ );
00106 }
00107 readPointer->next->next=writePointer;
00108 readPointer=writePointer;
00109 readAheadPointer=readPointer;
00110 writeAheadPointer=writePointer;
00111 readCount=writeCount=0;
00112 }
00113
00114 template <class SingleProducerConsumerType>
00115 SingleProducerConsumer<SingleProducerConsumerType>::~SingleProducerConsumer()
00116 {
00117 volatile DataPlusPtr *next;
00118 readPointer=writeAheadPointer->next;
00119 while (readPointer!=writeAheadPointer)
00120 {
00121 next=readPointer->next;
00122 RakNet::OP_DELETE((char*) readPointer, __FILE__, __LINE__);
00123 readPointer=next;
00124 }
00125 RakNet::OP_DELETE((char*) readPointer, __FILE__, __LINE__);
00126 }
00127
00128 template <class SingleProducerConsumerType>
00129 SingleProducerConsumerType* SingleProducerConsumer<SingleProducerConsumerType>::WriteLock( void )
00130 {
00131 if (writeAheadPointer->next==readPointer ||
00132 writeAheadPointer->next->readyToRead==true)
00133 {
00134 volatile DataPlusPtr *originalNext=writeAheadPointer->next;
00135 writeAheadPointer->next=RakNet::OP_NEW<DataPlusPtr>(__FILE__, __LINE__);
00136 RakAssert(writeAheadPointer->next);
00137 writeAheadPointer->next->next=originalNext;
00138 }
00139
00140 volatile DataPlusPtr *last;
00141 last=writeAheadPointer;
00142 writeAheadPointer=writeAheadPointer->next;
00143
00144 return (SingleProducerConsumerType*) last;
00145 }
00146
00147 template <class SingleProducerConsumerType>
00148 void SingleProducerConsumer<SingleProducerConsumerType>::CancelWriteLock( SingleProducerConsumerType* cancelToLocation )
00149 {
00150 writeAheadPointer=(DataPlusPtr *)cancelToLocation;
00151 }
00152
00153 template <class SingleProducerConsumerType>
00154 void SingleProducerConsumer<SingleProducerConsumerType>::WriteUnlock( void )
00155 {
00156
00157
00158 #ifdef _DEBUG
00159 RakAssert(writePointer->next!=readPointer);
00160 RakAssert(writePointer!=writeAheadPointer);
00161 #endif
00162
00163 writeCount++;
00164
00165 writePointer->readyToRead=true;
00166 writePointer=writePointer->next;
00167 }
00168
00169 template <class SingleProducerConsumerType>
00170 SingleProducerConsumerType* SingleProducerConsumer<SingleProducerConsumerType>::ReadLock( void )
00171 {
00172 if (readAheadPointer==writePointer ||
00173 readAheadPointer->readyToRead==false)
00174 {
00175 return 0;
00176 }
00177
00178 volatile DataPlusPtr *last;
00179 last=readAheadPointer;
00180 readAheadPointer=readAheadPointer->next;
00181 return (SingleProducerConsumerType*)last;
00182 }
00183
00184 template <class SingleProducerConsumerType>
00185 void SingleProducerConsumer<SingleProducerConsumerType>::CancelReadLock( SingleProducerConsumerType* cancelToLocation )
00186 {
00187 #ifdef _DEBUG
00188 RakAssert(readPointer!=writePointer);
00189 #endif
00190 readAheadPointer=(DataPlusPtr *)cancelToLocation;
00191 }
00192
00193 template <class SingleProducerConsumerType>
00194 void SingleProducerConsumer<SingleProducerConsumerType>::ReadUnlock( void )
00195 {
00196 #ifdef _DEBUG
00197 RakAssert(readAheadPointer!=readPointer);
00198 RakAssert(readPointer!=writePointer);
00199 #endif
00200 readCount++;
00201
00202
00203 readPointer->readyToRead=false;
00204 readPointer=readPointer->next;
00205 }
00206
00207 template <class SingleProducerConsumerType>
00208 void SingleProducerConsumer<SingleProducerConsumerType>::Clear( void )
00209 {
00210
00211 volatile DataPlusPtr *next;
00212 writePointer=readPointer->next;
00213
00214 int listSize=1;
00215 next=readPointer->next;
00216 while (next!=readPointer)
00217 {
00218 listSize++;
00219 next=next->next;
00220 }
00221
00222 while (listSize-- > MINIMUM_LIST_SIZE)
00223 {
00224 next=writePointer->next;
00225 #ifdef _DEBUG
00226 RakAssert(writePointer!=readPointer);
00227 #endif
00228 RakNet::OP_DELETE((char*) writePointer, __FILE__, __LINE__);
00229 writePointer=next;
00230 }
00231
00232 readPointer->next=writePointer;
00233 writePointer=readPointer;
00234 readAheadPointer=readPointer;
00235 writeAheadPointer=writePointer;
00236 readCount=writeCount=0;
00237 }
00238
00239 template <class SingleProducerConsumerType>
00240 int SingleProducerConsumer<SingleProducerConsumerType>::Size( void ) const
00241 {
00242 return writeCount-readCount;
00243 }
00244
00245 template <class SingleProducerConsumerType>
00246 bool SingleProducerConsumer<SingleProducerConsumerType>::CheckReadUnlockOrder(const SingleProducerConsumerType* data) const
00247 {
00248 return const_cast<const SingleProducerConsumerType *>(&readPointer->object) == data;
00249 }
00250
00251
00252 template <class SingleProducerConsumerType>
00253 bool SingleProducerConsumer<SingleProducerConsumerType>::ReadIsLocked(void) const
00254 {
00255 return readAheadPointer!=readPointer;
00256 }
00257 }
00258
00259 #endif