libDwm-0.6.0
DwmConcurrentQueue.hh
Go to the documentation of this file.
1 //===========================================================================
2 // @(#) $DwmPath: dwm/libDwm/tags/libDwm-0.6.0/include/DwmConcurrentQueue.hh 9014 $
3 // @(#) $Id: DwmConcurrentQueue.hh 9014 2017-04-11 09:53:02Z dwm $
4 //===========================================================================
5 // Copyright (c) Daniel W. McRobb 2016
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 // 1. Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // 2. Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // 3. The names of the authors and copyright holders may not be used to
18 // endorse or promote products derived from this software without
19 // specific prior written permission.
20 //
21 // IN NO EVENT SHALL DANIEL W. MCROBB BE LIABLE TO ANY PARTY FOR
22 // DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
23 // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE,
24 // EVEN IF DANIEL W. MCROBB HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
25 // DAMAGE.
26 //
27 // THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND
28 // DANIEL W. MCROBB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
29 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. DANIEL W. MCROBB MAKES NO
30 // REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER
31 // IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 // WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,
33 // OR THAT THE USE OF THIS SOFTWARE WILL NOT INFRINGE ANY PATENT,
34 // TRADEMARK OR OTHER RIGHTS.
35 //===========================================================================
36 
37 //---------------------------------------------------------------------------
40 //---------------------------------------------------------------------------
41 
42 #ifndef _DWMCONCURRENTQUEUE_HH_
43 #define _DWMCONCURRENTQUEUE_HH_
44 
45 extern "C" {
46  #include <unistd.h>
47 }
48 
49 #include <atomic>
50 #include <memory>
51 #include <thread>
52 #include <vector>
53 
54 namespace Dwm {
55 
56  namespace Thread {
57 
58  //------------------------------------------------------------------------
90  //------------------------------------------------------------------------
91  template <typename T>
93  {
94  public:
95  //----------------------------------------------------------------------
100  //----------------------------------------------------------------------
101  ConcurrentQueue(uint64_t maxLength = 10000,
102  useconds_t pushSleepUsecs = 1000)
103  : _length(0), _maxLength(maxLength),
104  _pushSleepUsecs(pushSleepUsecs)
105  {
106  _front = _back = new Entry(T());
107  _pushingLocked = _poppingLocked = false;
108  }
109 
110  //----------------------------------------------------------------------
112  //----------------------------------------------------------------------
114  {
115  while (_front != nullptr) {
116  Entry *tmp = _front;
117  _front = tmp->next;
118  delete tmp;
119  }
120  }
121 
122  //----------------------------------------------------------------------
126  //----------------------------------------------------------------------
127  bool PopFront(T & result)
128  {
129  while (_poppingLocked.exchange(true));
130  if (_front->next != nullptr) {
131  // queue is not empty.
132  Entry *oldFirst = _front;
133  _front = _front->next;
134  result = _front->value;
135  _poppingLocked = false;
136  // delete the old front Entry.
137  delete oldFirst;
138  // decrement the queue length.
139  --_length;
140  return true;
141  }
142  _poppingLocked = false;
143  return false;
144  }
145 
146  //----------------------------------------------------------------------
148  //----------------------------------------------------------------------
149  bool PopFront(std::vector<T> & result)
150  {
151  typename std::vector<T>::size_type numEntries = 0;
152  // lcok against others popping from the queue
153  while (_poppingLocked.exchange(true));
154  if (_front->next != nullptr) {
155  // queue is not empty. Save the existing front.
156  Entry *oldFront = _front;
157  // Move front to the end of the queue since we're going to take
158  // all entries from the queue. Keep track of how many entries
159  // we'll take, and adjust _length at end.
160  while (_front->next != nullptr) {
161  _front = _front->next;
162  ++numEntries;
163  }
164  _length -= numEntries;
165  // Save the new location of _front. This is where we'll stop
166  // popping entries. Once we unlock popping, another thread
167  // could come in and move _front.
168  Entry *newFront = _front;
169  // Unlock popping so other threads can pop entries.
170  _poppingLocked = false;
171  // Resize the output vector to hold the popped entries.
172  result.resize(numEntries);
173  // Populate the output vector and delete the old entries.
174  typename std::vector<T>::size_type i = 0;
175  Entry *entry = oldFront->next;
176  while (entry != newFront) {
177  Entry *delEntry = entry;
178  result[i] = entry->value;
179  entry = entry->next;
180  ++i;
181  delete delEntry;
182  }
183  // Delete the old front entry.
184  delete oldFront;
185  return true;
186  }
187  _poppingLocked = false;
188  return false;
189  }
190 
191  //----------------------------------------------------------------------
194  //----------------------------------------------------------------------
195  bool PushBack(const T & t)
196  {
197  while (_length > _maxLength) { usleep(_pushSleepUsecs); };
198  Entry *tmp = new Entry(t);
199  while (_pushingLocked.exchange(true));
200  _back->next = tmp;
201  _back = tmp;
202  _pushingLocked = false;
203  ++_length;
204  return true;
205  }
206 
207  //----------------------------------------------------------------------
209  //----------------------------------------------------------------------
210  bool PushBack(const std::vector<T> & t)
211  {
212  while (_length > _maxLength) { usleep(_pushSleepUsecs); }
213  std::vector<Entry *> newEntries(t.size());
214  typename std::vector<T>::size_type i = 0;
215  newEntries[i] = new Entry(t[i]);
216  ++i;
217  for (; i < t.size(); ++i) {
218  newEntries[i] = new Entry(t[i]);
219  newEntries[i-1]->next = newEntries[i];
220  }
221  while (_pushingLocked.exchange(true));
222  _back->next = newEntries[0];
223  _back = newEntries[t.size() - 1];
224  _pushingLocked = false;
225  _length += t.size();
226  return true;
227  }
228 
229  private:
230  //----------------------------------------------------------------------
232  //----------------------------------------------------------------------
233  class Entry
234  {
235  public:
236  Entry(const T & val)
237  : value(val), next(nullptr)
238  {}
239  T value;
240  std::atomic<Entry *> next;
241  };
242 
243  Entry *_front;
244  std::atomic<bool> _poppingLocked;
245  Entry *_back;
246  std::atomic<bool> _pushingLocked;
247  std::atomic<uint64_t> _length;
248  uint64_t _maxLength;
249  useconds_t _pushSleepUsecs;
250  };
251 
252 
253  } // namespace Thread
254 
255 } // namespace Dwm
256 
257 #endif // _DWMCONCURRENTQUEUE_HH_
258 
259 //---------------------------- emacs settings -----------------------------
260 // Local Variables:
261 // mode: C++
262 // tab-width: 2
263 // indent-tabs-mode: nil
264 // c-basic-offset: 2
265 // End:
266 //-------------------------------------------------------------------------
~ConcurrentQueue()
Destructor. Walks the queue and deletes all entries.
Definition: DwmConcurrentQueue.hh:113
bool PushBack(const T &t)
Waits for the queue to not be full (see the Queue constructor), then pushes t onto the back of the qu...
Definition: DwmConcurrentQueue.hh:195
ConcurrentQueue(uint64_t maxLength=10000, useconds_t pushSleepUsecs=1000)
Constructor.
Definition: DwmConcurrentQueue.hh:101
bool PopFront(T &result)
If the queue is not empty, pops the front entry into result and returns true.
Definition: DwmConcurrentQueue.hh:127
Definition: DwmBZ2IO.hh:67
Concurrent queue template.
Definition: DwmConcurrentQueue.hh:92