i6engine  1.0
DoubleBufferQueue.h
Go to the documentation of this file.
1 /*
2  * i6engine
3  * Copyright (2016) Daniel Bonrath, Michael Baer, All rights reserved.
4  *
5  * This file is part of i6engine; i6engine 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 __I6ENGINE_UTILS_DOUBLEBUFFERQUEUE_H__
26 #define __I6ENGINE_UTILS_DOUBLEBUFFERQUEUE_H__
27 
28 #include <queue>
29 
31 
32 #include "boost/thread/mutex.hpp"
33 
34 namespace i6e {
35 namespace utils {
36 
44  template<typename T, bool producer = true, bool consumer = true>
46  private:
47  template<bool v>
48  struct Bool2Type {
49  enum {
50  value = v
51  };
52  };
53 
54  public:
58  DoubleBufferQueue() : _queueA(), _queueB(), _queueRead(&_queueA), _queueWrite(&_queueB), _readLock(), _writeLock() {
59  }
60 
64  void push(const T & value) {
65  boost::mutex::scoped_lock scopeLock(_writeLock);
66  _queueWrite->push(value);
67  }
68 
72  void pop() {
73  pop(Bool2Type<consumer>());
74  }
75 
79  T front() {
80  return front(Bool2Type<consumer>());
81  }
82 
86  T poll() {
87  return poll(Bool2Type<consumer>());
88  }
89 
93  inline bool empty() const {
94  return _queueRead->empty() && _queueWrite->empty();
95  }
96 
100  inline size_t size() const {
101  return _queueRead->size() + _queueWrite->size();
102  }
103 
107  void clear() {
108  _readLock.lock();
109  while (!_queueRead->empty()) {
110  _queueRead->pop();
111  }
112  _readLock.unlock();
113  _writeLock.lock();
114  while (!_queueWrite->empty()) {
115  _queueWrite->pop();
116  }
117  _writeLock.unlock();
118  }
119 
120  private:
124  std::queue<T> _queueA;
125  std::queue<T> _queueB;
126 
130  std::queue<T> * _queueRead;
131  std::queue<T> * _queueWrite;
132 
133  boost::mutex _readLock;
134  boost::mutex _writeLock;
135 
136  void pop(Bool2Type<true>) {
137  static_assert(consumer, "Consumer must be true here");
138  boost::mutex::scoped_lock scopeLock(_readLock);
139  if (_queueRead->empty()) {
140  swap();
141 
142  if (_queueRead->empty()) {
143  ISIXE_THROW_API("DoubleBufferQueue", "nothing to pop");
144  }
145  }
146 
147  _queueRead->pop();
148  }
149 
150  void pop(Bool2Type<false>) {
151  static_assert(!consumer, "Consumer must be false here");
152  if (_queueRead->empty()) {
153  swap();
154 
155  if (_queueRead->empty()) {
156  ISIXE_THROW_API("DoubleBufferQueue", "nothing to pop");
157  }
158  }
159 
160  _queueRead->pop();
161  }
162 
163  T front(Bool2Type<true>) {
164  static_assert(consumer, "Consumer must be true here");
165  boost::mutex::scoped_lock scopeLock(_readLock);
166  if (_queueRead->empty()) {
167  swap();
168 
169  if (_queueRead->empty()) {
170  ISIXE_THROW_API("DoubleBufferQueue", "nothing to get");
171  }
172  }
173  return _queueRead->front();
174  }
175 
176  T front(Bool2Type<false>) {
177  static_assert(!consumer, "Consumer must be false here");
178  if (_queueRead->empty()) {
179  swap();
180 
181  if (_queueRead->empty()) {
182  ISIXE_THROW_API("DoubleBufferQueue", "nothing to get");
183  }
184  }
185  return _queueRead->front();
186  }
187 
188  T poll(Bool2Type<true> b) {
189  static_assert(consumer, "Consumer must be true here");
190  boost::mutex::scoped_lock scopeLock(_readLock);
191  if (_queueRead->empty()) {
192  swap();
193 
194  if (_queueRead->empty()) {
195  ISIXE_THROW_API("DoubleBufferQueue", "nothing to get");
196  }
197  }
198 
199  T ret = _queueRead->front();
200  _queueRead->pop();
201  return ret;
202  }
203 
204  T poll(Bool2Type<false> b) {
205  static_assert(!consumer, "Consumer must be false here");
206  if (_queueRead->empty()) {
207  swap();
208 
209  if (_queueRead->empty()) {
210  ISIXE_THROW_API("DoubleBufferQueue", "nothing to get");
211  }
212  }
213 
214  T ret = _queueRead->front();
215  _queueRead->pop();
216  return ret;
217  }
218 
222  void swap() {
223  boost::mutex::scoped_lock scopeLock2(_writeLock);
224  if (_queueRead == &_queueA) {
225  _queueWrite = &_queueA;
226  _queueRead = &_queueB;
227  } else {
228  _queueWrite = &_queueB;
229  _queueRead = &_queueA;
230  }
231  }
232 
236  DoubleBufferQueue(const DoubleBufferQueue &) = delete;
237  };
238 
239 } /* namespace utils */
240 } /* namespace i6e */
241 
242 #endif /* __I6ENGINE_UTILS_DOUBLEBUFFERQUEUE_H__ */
243 
void clear()
removes all elements in the queue
DoubleBufferQueue()
default constructor
void pop()
removes first entry of the queue
#define ISIXE_THROW_API(module, message)
Definition: Exceptions.h:45
size_t size() const
returns size of the queue
T front()
returns first entry of the queue
T poll()
removes first entry of the queue and returns its value
void push(const T &value)
pushes the given value into the queue
bool empty() const
returns true if the queue is empty, otherwise false