clockUtils  1.1
LockFreeQueue.h
Go to the documentation of this file.
1 /*
2  * clockUtils
3  * Copyright (2016) Michael Baer, Daniel Bonrath, All rights reserved.
4  *
5  * This file is part of clockUtils; clockUtils is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
25 #ifndef __CLOCKUTILS_CONTAINER_LOCKFREEQUEUE_H__
26 #define __CLOCKUTILS_CONTAINER_LOCKFREEQUEUE_H__
27 
28 #include <array>
29 #include <atomic>
30 #include <cassert>
31 
32 #include "clockUtils/errors.h"
33 
35 
36 namespace clockUtils {
37 namespace container {
38 
45  template<typename T, size_t SIZE>
46  class LockFreeQueue {
47  public:
51  LockFreeQueue() : _readIndex(0), _writeIndex(0), _enqueuing(false), _dequeuing(false), _data() {
52  }
53 
57  ClockError push(const T & value) {
58  bool enqueueing = false;
59  while (!std::atomic_compare_exchange_strong(&_enqueuing, &enqueueing, true)) {
60  enqueueing = false;
61  }
62  assert(!enqueueing);
63  assert(_enqueuing);
64  uint64_t readIndex = _readIndex;
65  uint64_t writeIndex = _writeIndex;
67  if (writeIndex - readIndex < SIZE || readIndex > writeIndex) {
68  _data[writeIndex % SIZE] = value;
69  _writeIndex.fetch_add(1);
70  } else {
72  }
73  _enqueuing.exchange(false);
74  return err;
75  }
76 
81  bool dequeueing = false;
82  while (!std::atomic_compare_exchange_strong(&_dequeuing, &dequeueing, true)) {
83  dequeueing = false;
84  }
85  assert(!dequeueing);
86  assert(_dequeuing);
87  uint64_t writeIndex = _writeIndex;
89  if (writeIndex <= _readIndex) {
91  } else {
92  _readIndex.fetch_add(1);
93  }
94  _dequeuing.exchange(false);
95  return err;
96  }
97 
101  ClockError front(T & value) {
102  bool dequeueing = false;
103  while (!std::atomic_compare_exchange_strong(&_dequeuing, &dequeueing, true)) {
104  dequeueing = false;
105  }
106  assert(!dequeueing);
107  assert(_dequeuing);
108  uint64_t writeIndex = _writeIndex;
109  uint64_t readIndex = _readIndex;
111  if (writeIndex > readIndex) {
112  value = _data[readIndex % SIZE];
113  } else {
115  }
116  _dequeuing.exchange(false);
117  return err;
118  }
119 
123  ClockError poll(T & value) {
124  bool dequeueing = false;
125  while (!std::atomic_compare_exchange_strong(&_dequeuing, &dequeueing, true)) {
126  dequeueing = false;
127  }
128  assert(!dequeueing);
129  assert(_dequeuing);
130  uint64_t writeIndex = _writeIndex;
131  uint64_t readIndex = _readIndex;
133  if (writeIndex > readIndex) {
134  value = _data[readIndex % SIZE];
135  _readIndex.fetch_add(1);
136  } else {
138  }
139  _dequeuing.exchange(false);
140  return err;
141  }
142 
146  inline bool empty() const {
147  uint64_t readIdx = _readIndex;
148  uint64_t writeIdx = _writeIndex;
149  return readIdx == writeIdx;
150  }
151 
155  inline size_t size() const {
156  uint64_t readIdx = _readIndex;
157  uint64_t writeIdx = _writeIndex;
158  return size_t(writeIdx - readIdx);
159  }
160 
164  void clear() {
165  _readIndex.store(_writeIndex);
166  }
167 
168  private:
169  std::atomic<uint64_t> _readIndex;
170  std::atomic<uint64_t> _writeIndex;
171  std::atomic<bool> _enqueuing;
172  std::atomic<bool> _dequeuing;
173 
174  std::array<T, SIZE> _data;
175 
179  LockFreeQueue(const LockFreeQueue &) = delete;
180  };
181 
182 } /* namespace container */
183 } /* namespace clockUtils */
184 
185 #endif /* __CLOCKUTILS_CONTAINER_LOCKFREEQUEUE_H__ */
186 
bool empty() const
returns true if the queue is empty, otherwise false
size_t size() const
returns size of the queue
LockFreeQueue()
default constructor
Definition: LockFreeQueue.h:51
ClockError front(T &value)
returns first entry of the queue, but keeps it in the queue
0x11 no more space available in container
ClockError push(const T &value)
pushes the given value into the queue
Definition: LockFreeQueue.h:57
ClockError pop()
removes first entry of the queue
Definition: LockFreeQueue.h:80
void clear()
removes all elements in the queue
0x10 no element available
0x0 method call succeeded
ClockError poll(T &value)
removes first entry of the queue and returns its value
ClockError
Definition: errors.h:30