My Project
ParaRingBuffer.h
1 #pragma once
2 #include <boost/circular_buffer.hpp>
3 #include <boost/thread.hpp>
4 #include "util/mutex.h"
5 #include <queue>
6 
7 
8 namespace ParaEngine
9 {
16  template <class T>
18  {
19  public:
20  typedef boost::circular_buffer<T> container_type;
21  typedef typename container_type::size_type size_type;
22  typedef typename container_type::value_type value_type;
23 
24  enum BufferStatus
25  {
26  BufferOverFlow = 0,
27  BufferFull = 1,
28  BufferNormal = 2,
29  BufferEmpty = 3,
30  BufferFirst = 3,
31  };
32 
33  explicit CParaRingBuffer(size_type capacity) : m_container(capacity) {}
34 
35  public:
42  BufferStatus try_push(const value_type& item)
43  {
44  Lock lock(m_mutex);
45  if(m_container.full())
46  {
47  return BufferOverFlow;
48  }
49  else
50  {
51  BufferStatus bufferStatus = m_container.empty() ? BufferFirst : BufferNormal;
52  m_container.push_back(item);
53  return m_container.full() ? BufferFull : bufferStatus;
54  }
55  }
56 
62  BufferStatus try_push_get_front(const value_type& item, value_type** ppFrontItem)
63  {
64  Lock lock(m_mutex);
65  if(m_container.full())
66  {
67  return BufferOverFlow;
68  }
69  else
70  {
71  BufferStatus bufferStatus = m_container.empty() ? BufferFirst : BufferNormal;
72  m_container.push_back(item);
73  *ppFrontItem = &(m_container.front());
74  return m_container.full() ? BufferFull : bufferStatus;
75  }
76  }
77 
82  void push_front(const value_type& item)
83  {
84  Lock lock(m_mutex);
85  m_container.push_front(item);
86  }
87 
93  BufferStatus try_push_array(const value_type* pItems, int nCount)
94  {
95  Lock lock(m_mutex);
96  if(m_container.capacity()<nCount)
97  {
98  return BufferFull;
99  }
100  else
101  {
102  BufferStatus bufferStatus = m_container.empty() ? BufferFirst : BufferNormal;
103  for (int i=0; i<nCount;++i)
104  {
105  m_container.push_back(*(pItems+i));
106  }
107  return m_container.full() ? BufferFull : bufferStatus;
108  }
109  }
110 
115  value_type * try_front()
116  {
117  Lock lock(m_mutex);
118  return m_container.empty() ? NULL : &(m_container.front());
119  }
120 
126  bool try_pop(value_type& item)
127  {
128  Lock lock(m_mutex);
129  if(m_container.empty())
130  {
131  return false;
132  }
133  else
134  {
135  item = m_container.front();
136  m_container.pop_front();
137  return true;
138  }
139  }
140 
146  bool try_next(value_type** ppItem)
147  {
148  Lock lock(m_mutex);
149  if(m_container.empty())
150  {
151  return false;
152  }
153  else
154  {
155  m_container.pop_front();
156  if(ppItem!=0 && !m_container.empty())
157  {
158  *ppItem = &(m_container.front());
159  }
160  return true;
161  }
162  }
163 
164  size_type size() const {
165  Lock lock(m_mutex);
166  return m_container.size();
167  };
168  bool empty() const {
169  Lock lock(m_mutex);
170  return m_container.empty();
171  };
172  bool full() const {
173  Lock lock(m_mutex);
174  return m_container.full();
175  };
176  public:
177  container_type m_container;
178  mutex m_mutex;
179  };
180 
187  template<typename Data>
189  {
190  protected:
191  typedef boost::circular_buffer<Data> container_type;
192  typedef typename container_type::size_type size_type;
193  typedef typename container_type::value_type value_type;
194 
195  mutable boost::mutex m_mutex;
196  boost::condition_variable m_condition_variable;
197 
203 
204  container_type m_container;
205  public:
206  enum BufferStatus
207  {
208  BufferOverFlow = 0,
209  BufferFull = 1,
210  BufferNormal = 2,
211  BufferEmpty = 3,
212  BufferFirst = 3,
213  };
214 
215  explicit concurrent_queue(size_type capacity) : m_container(capacity),m_use_event(true) {}
216 
221  void SetUseEvent(bool bUseEvent)
222  {
223  boost::mutex::scoped_lock lock(m_mutex);
224  m_use_event = bUseEvent;
225  }
226 
233  BufferStatus try_push(value_type& item)
234  {
235  boost::mutex::scoped_lock lock(m_mutex);
236  BufferStatus bufferStatus = m_container.empty() ? BufferFirst : BufferNormal;
237  if(m_container.full())
238  {
239  bufferStatus = BufferOverFlow;
240  }
241  else
242  {
243  m_container.push_back(item);
244  bufferStatus = m_container.full() ? BufferFull : bufferStatus;
245  }
246  lock.unlock();
247  if(m_use_event)
248  m_condition_variable.notify_one();
249  return bufferStatus;
250  }
251 
255  void push(value_type& data)
256  {
257  boost::mutex::scoped_lock lock(m_mutex);
258  m_container.push_back(data);
259  lock.unlock();
260  if(m_use_event)
261  m_condition_variable.notify_one();
262  }
263 
268  void push_front(value_type & data)
269  {
270  boost::mutex::scoped_lock lock(m_mutex);
271  m_container.push_front(data);
272  lock.unlock();
273  m_condition_variable.notify_one();
274  }
275 
276  bool empty() const
277  {
278  boost::mutex::scoped_lock lock(m_mutex);
279  return m_container.empty();
280  }
281 
282  bool try_pop(value_type& popped_value)
283  {
284  boost::mutex::scoped_lock lock(m_mutex);
285  if(m_container.empty())
286  {
287  return false;
288  }
289 
290  popped_value=m_container.front();
291  m_container.pop_front();
292  return true;
293  }
294 
295  void wait_and_pop(value_type& popped_value)
296  {
297  boost::mutex::scoped_lock lock(m_mutex);
298  while(m_container.empty())
299  {
300  m_condition_variable.wait(lock);
301  }
302  popped_value=m_container.front();
303  m_container.pop_front();
304  }
305  };
306 }
BufferStatus try_push(const value_type &item)
try push to back of the queue.
Definition: ParaRingBuffer.h:42
bool m_use_event
whether to use event to inform consumer when new data items are added to the queue.
Definition: ParaRingBuffer.h:202
it implements a producer/consumer(s) queue design pattern.
Definition: ParaRingBuffer.h:188
void push_front(value_type &data)
add a data item to the front of the queue.
Definition: ParaRingBuffer.h:268
different physics engine has different winding order.
Definition: EventBinding.h:32
simple scoped lock function
Definition: mutex.h:12
BufferStatus try_push(value_type &item)
try push to back of the queue.
Definition: ParaRingBuffer.h:233
void push_front(const value_type &item)
push to the front of the queue.
Definition: ParaRingBuffer.h:82
bool try_next(value_type **ppItem)
try pop from the front of the queue and return the front object after the pop.
Definition: ParaRingBuffer.h:146
void push(value_type &data)
add a data item to the back of the queue.
Definition: ParaRingBuffer.h:255
BufferStatus try_push_get_front(const value_type &item, value_type **ppFrontItem)
same as try_push, except that it also returns pointer to the front object.
Definition: ParaRingBuffer.h:62
cross platform mutex
Definition: mutex.h:95
bool try_pop(value_type &item)
try pop from the front of the queue.
Definition: ParaRingBuffer.h:126
void SetUseEvent(bool bUseEvent)
whether to use event to inform consumer when new data items are added to the queue.
Definition: ParaRingBuffer.h:221
CParaRingBuffer is normally used in a producer-consumer mode when producer threads produce items and ...
Definition: ParaRingBuffer.h:17
BufferStatus try_push_array(const value_type *pItems, int nCount)
try push to back of the queue.
Definition: ParaRingBuffer.h:93
value_type * try_front()
Definition: ParaRingBuffer.h:115