• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

SingleProducerConsumer.h

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                 // Constructor
00029                 SingleProducerConsumer();
00030 
00031                 // Destructor
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                 // Cancelling locks cancels all locks back up to the data passed.  So if you lock twice and cancel using the first lock, the second lock is ignored
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                         // Ready to read is so we can use an equality boolean comparison, in case the writePointer var is trashed while context switching.
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                 // Preallocate
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; // last to next = start
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                 //      DataPlusPtr *dataContainer = (DataPlusPtr *)structure;
00157 
00158 #ifdef _DEBUG
00159                 RakAssert(writePointer->next!=readPointer);
00160                 RakAssert(writePointer!=writeAheadPointer);
00161 #endif
00162 
00163                 writeCount++;
00164                 // User is done with the data, allow send by updating the write pointer
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); // If hits, then called ReadUnlock before ReadLock
00198                 RakAssert(readPointer!=writePointer); // If hits, then called ReadUnlock when Read returns 0
00199 #endif
00200                 readCount++;
00201 
00202                 // Allow writes to this memory block
00203                 readPointer->readyToRead=false;
00204                 readPointer=readPointer->next;
00205         }
00206 
00207         template <class SingleProducerConsumerType>
00208                 void SingleProducerConsumer<SingleProducerConsumerType>::Clear( void )
00209         {
00210                 // Shrink the list down to MINIMUM_LIST_SIZE elements
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

Generated on Thu Sep 30 2010 01:27:28 for RakNet by  doxygen 1.7.1