ADTF  3.18.2
lockfreequeue.h
Go to the documentation of this file.
1 
7 #ifndef _LOCK_FREE_QUEUE_CLASS_HEADER_
8 #define _LOCK_FREE_QUEUE_CLASS_HEADER_
9 
10 #ifndef A_UTILS_TAGGED_POINTER_AVALIABLE
11  #include <queue>
12 #endif
13 
14 namespace A_UTILS_NS
15 {
16 
17 
18 #ifdef A_UTILS_TAGGED_POINTER_AVALIABLE
19 
35 template <class T>
36 class A_UTILS_CAS_ALIGNMENT lock_free_queue
37 {
38  protected:
39 
43  struct A_UTILS_CAS_ALIGNMENT cNode
44  {
45  tagged_ptr<cNode> m_pNext;
46  T m_oData;
47  };
48 
50  typedef tagged_ptr<cNode> tTaggedNodePtr;
51 
53  tTaggedNodePtr m_pHead;
54 
56  tTaggedNodePtr m_pTail;
57 
59  free_list<cNode, T> m_oFree;
60 
61  public:
62 
71  lock_free_queue(tUInt nReserve = 0, tBool bGrow = tTrue): m_pHead(nullptr), m_pTail(nullptr), m_oFree(nReserve, bGrow)
72  {
73  m_pHead.Set(new cNode);
74  m_pTail = m_pHead;
75  }
76 
80  virtual ~lock_free_queue()
81  {
82  // clear stack
83  T oTmp;
84  while ((ERR_NOERROR) == Pop(&oTmp));
85  delete m_pHead.GetPtr();
86  }
87 
94  tResult Push(const T& oValue)
95  {
96  // get a node from the free list
97  cNode* pTmp = m_oFree.GetFreeNode();
98  if (!pTmp)
99  {
100  return (ERR_MEMORY);
101  }
102 
103  // store the value
104  pTmp->m_oData = oValue;
105  // increase tag to avoid ABA problem
106  pTmp->m_pNext.Set(nullptr, pTmp->m_pNext.GetTag() + 1);
107 
108  // and insert it into the list
109  for (;;)
110  {
111  tTaggedNodePtr pTail = m_pTail;
112 
113  memory_barrier();
114 
115  tTaggedNodePtr pNext = pTail->m_pNext;
116 
117  if (pTail == m_pTail)
118  {
119  if (!pNext)
120  {
121  if (pTail->m_pNext.CompareAndSwap(pNext, pTmp))
122  {
123  m_pTail.CompareAndSwap(pTail, pTmp);
124  break;
125  }
126  }
127  else
128  {
129  m_pTail.CompareAndSwap(pTail, pNext.GetPtr());
130  }
131  }
132  }
133 
134  return (ERR_NOERROR);
135  }
136 
144  tResult Pop(T* pValue)
145  {
146  for (;;)
147  {
148  tTaggedNodePtr pHead = m_pHead;
149 
150  memory_barrier();
151 
152  tTaggedNodePtr pTail = m_pTail;
153 
154  memory_barrier();
155 
156  cNode* pNext = pHead->m_pNext.GetPtr();
157 
158  if (pHead == m_pHead)
159  {
160  if (pHead.GetPtr() == pTail.GetPtr())
161  {
162  if (pNext == nullptr)
163  {
164  return (ERR_EMPTY);
165  }
166 
167  m_pTail.CompareAndSwap(pTail, pNext);
168  }
169  else
170  {
171  if (pNext == nullptr)
172  {
173  continue;
174  }
175 
176  *pValue = pNext->m_oData;
177  if (m_pHead.CompareAndSwap(pHead, pNext))
178  {
179  m_oFree.AddFreeNode(pHead.GetPtr());
180  break;
181  }
182  }
183  }
184  }
185 
186  return (ERR_NOERROR);
187  }
188 
189  private:
190  lock_free_queue(const lock_free_queue& oOther);
191 };
192 
193 #else
194 
206 template <class T>
208 {
209  protected:
210  std::queue<T> m_oQueue;
211  std::recursive_mutex m_oMutex;
212  public:
213 
221  lock_free_queue(tUInt nReserve = 0, tBool bGrow = tTrue)
222  {
223  }
224 
229  {
230  }
231 
237  tResult Push(const T& oValue)
238  {
239  std::lock_guard<std::recursive_mutex> oLck(m_oMutex);
240  m_oQueue.push(oValue);
241  return (ERR_NOERROR);
242  }
243 
250  tResult Pop(T* pValue)
251  {
252  std::lock_guard<std::recursive_mutex> oLck(m_oMutex);
253  if (m_oQueue.empty())
254  {
255  return (ERR_EMPTY);
256  }
257  *pValue = m_oQueue.front();
258  m_oQueue.pop();
259  return (ERR_NOERROR);
260  }
261 
262  private:
263  lock_free_queue(const lock_free_queue& oOther);
264 };
265 
266 #endif
267 
268 }
269 
270 #endif
unsigned int tUInt
type definition for unsigned integer value (platform and compiler dependent type).
bool tBool
The tBool defines the type for the Values tTrue and tFalse (platform and compiler dependent).
Lock-free queue (FIFO) class that allows multiple writers and readers.
lock_free_queue(tUInt nReserve=0, tBool bGrow=tTrue)
Constructor.
tResult Push(const T &oValue)
Pushes an element into the queue.
tResult Pop(T *pValue)
Pops an element from the queue.
virtual ~lock_free_queue()
Destructor.
#define tTrue
Value for tBool.
Definition: constants.h:62
ADTF A_UTIL Namespace - Within adtf this is used as adtf::util or adtf_util.
Definition: d_ptr.h:11
tVoid memory_barrier()
This method will help ensure that all memory reads and writes will have been performed before this fu...
Definition: tagged_ptr.h:70