LocklessQueue.h

Go to the documentation of this file.
00001 #ifndef __LDK_LOCKLESSQUEUE_HH__
00002 #define __LDK_LOCKLESSQUEUE_HH__
00003 
00005 //   Copyright (C) 2003-2006 Lorien Dunn.
00006 //
00007 //   Contact: loriendunn AT users DOT sourceforge DOT net
00008 //
00009 //   This software is provided 'as-is', without any express or implied warranty.
00010 //   In no event will the authors be held liable for any damages arising from
00011 //   the use of this software.
00012 //
00013 //   Permission is granted to anyone to use this software for any purpose,
00014 //   including commercial applications, and to alter it and redistribute it
00015 //   freely, subject to the following restrictions:
00016 //
00017 //   1. The origin of this software must not be misrepresented; you must not
00018 //   claim that you wrote the original software. If you use this software in a
00019 //   product, an acknowledgment in the product documentation would be
00020 //   appreciated but is not required.
00021 //
00022 //   2. Altered source versions must be plainly marked as such, and must not be
00023 //   misrepresented as being the original software.
00024 //
00025 //   3. This notice may not be removed or altered from any source distribution.
00026 //
00028 
00033 
00034 #include "LDK/Exceptions.h"
00035 #include "LDK/Atomic.h"
00036 #include <memory.h>
00037 
00038 namespace LDK
00039 {
00061 template <class T>
00062 class LocklessQueue
00063 {
00064     struct QType
00065     {
00066         AtomicCount mHead;
00067         AtomicCount mTail;
00068         T* mBuffer;
00069         Atomic<bool> mOverflow;
00070 
00071         inline QType(size_t size) : mHead(0),
00072          mTail(0),
00073          mBuffer(NULL),
00074          mOverflow(false)
00075         {
00076             mBuffer = reinterpret_cast<T*>(malloc(sizeof(T)*size));
00077             if(!mBuffer)
00078                 throw LDK_BADALLOC_ERROR;
00079         }
00080 
00081         inline ~QType()
00082         {
00083             if(mBuffer)
00084                 ::free(mBuffer);
00085         }
00086 
00087         inline const T* operator[](size_t idx) const
00088         {
00089             return &mBuffer[idx];
00090         }
00091 
00092         inline T* operator[](size_t idx)
00093         {
00094             return &mBuffer[idx];
00095         }
00096     };
00097 
00098     QType* mQueue;
00099     const size_t mSize;
00100 
00101 public:
00105     inline LocklessQueue(size_t size) : mQueue(NULL),
00106      mSize(size+1) //+1 because full == overflow
00107     {
00108         mQueue = new QType(mSize);
00109     }
00110 
00111     inline ~LocklessQueue()
00112     {
00113         if(mQueue)
00114             delete mQueue;
00115     }
00116 
00121     inline void enqueue(const T& msg)
00122     {
00123         size_t tail = mQueue->mTail;
00124         memcpy((*mQueue)[tail], &msg, sizeof(T));
00125         tail++;
00126         if(tail == mSize)
00127             tail = 0;
00128         if(tail == mQueue->mHead)
00129         {
00130             mQueue->mOverflow = true;
00131             throw LDK_LENGTH_ERROR("LocklessQueue overflow");
00132         }
00133         mQueue->mTail = tail;
00134     }
00135 
00140     inline void enqueue(const T* msg)
00141     {
00142         enqueue(*msg);
00143     }
00144 
00149     inline void dequeue(T& msg)
00150     {
00151         if(mQueue->mOverflow)
00152         {
00153             mQueue->mOverflow = false;
00154             return;
00155         }
00156 
00157         size_t head = mQueue->mHead; //make sure this is written after access
00158 
00159         if(head == mQueue->mTail)
00160             throw LDK_LENGTH_ERROR("LocklessQueue empty");
00161         memcpy(&msg, (*mQueue)[head], sizeof(T));
00162         head++;
00163         if(head == mSize)
00164             head = 0;
00165         mQueue->mHead = head;
00166     }
00167 
00172     inline void dequeue(T* msg)
00173     {
00174         dequeue(*msg);
00175     }
00176 
00179     inline bool full() const
00180     {
00181         size_t tail = mQueue->mTail + 1;
00182         if(tail == mSize)
00183             tail = 0;
00184         return (tail == mQueue->mHead);
00185     }
00186 
00189     inline bool empty() const
00190     {
00191         return (mQueue->mHead == mQueue->mTail);
00192     }
00193 
00196     inline const T* peek() const
00197     {
00198         size_t head = mQueue->mHead;
00199         if(head == mQueue->mTail)
00200             return NULL;
00201         return (*mQueue)[head];
00202     }
00203 
00204     inline void clear()
00205     {
00206         mQueue->mTail = 0;
00207         mQueue->mHead = 0;
00208         mQueue->mOverflow = 0;
00209     }
00210 };
00211 
00212 }//namespace LDK
00213 
00214 #endif //__LDK_LOCKLESSQUEUE_HH__

Generated on Fri Aug 17 18:32:26 2007 for LDK by  doxygen 1.5.1