libDwm-0.9.45
DwmThreadQueue.hh
Go to the documentation of this file.
1//===========================================================================
2// @(#) $DwmPath$
3//===========================================================================
4// Copyright (c) Daniel W. McRobb 2000-2007, 2016
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10//
11// 1. Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// 2. Redistributions in binary form must reproduce the above copyright
14// notice, this list of conditions and the following disclaimer in the
15// documentation and/or other materials provided with the distribution.
16// 3. The names of the authors and copyright holders may not be used to
17// endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// IN NO EVENT SHALL DANIEL W. MCROBB BE LIABLE TO ANY PARTY FOR
21// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
22// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE,
23// EVEN IF DANIEL W. MCROBB HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
24// DAMAGE.
25//
26// THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND
27// DANIEL W. MCROBB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
28// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. DANIEL W. MCROBB MAKES NO
29// REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER
30// IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31// WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,
32// OR THAT THE USE OF THIS SOFTWARE WILL NOT INFRINGE ANY PATENT,
33// TRADEMARK OR OTHER RIGHTS.
34//===========================================================================
35
36//---------------------------------------------------------------------------
39//---------------------------------------------------------------------------
40
41#ifndef _DWMTHREADQUEUE_HH_
42#define _DWMTHREADQUEUE_HH_
43
44#include <atomic>
45#include <deque>
46#include <iostream>
47#include <mutex>
48#include <condition_variable>
49#include <type_traits>
50
51namespace Dwm {
52
53 namespace Thread {
54
55 //------------------------------------------------------------------------
65 //------------------------------------------------------------------------
66 template <typename _ValueType>
67 class Queue
68 {
69 public:
70 //----------------------------------------------------------------------
72 //----------------------------------------------------------------------
74 : _maxLength(0), _queue(), _mutex(), _signalled(false),
75 _lock(_mutex), _cv()
76 {
77 _lock.unlock();
78 }
79
80 //----------------------------------------------------------------------
82 //----------------------------------------------------------------------
84 {
85 std::unique_lock<std::mutex> lk(_mutex);
86 _queue.clear();
87 }
88
89 //----------------------------------------------------------------------
92 //----------------------------------------------------------------------
93 uint32_t MaxLength() const
94 {
95 return(_maxLength);
96 }
97
98 //----------------------------------------------------------------------
101 //----------------------------------------------------------------------
102 uint32_t MaxLength(uint32_t maxLength)
103 {
104 _maxLength = maxLength;
105 return(_maxLength);
106 }
107
108 //----------------------------------------------------------------------
110 //----------------------------------------------------------------------
111 typename std::deque<_ValueType>::size_type Length() const
112 {
113 std::lock_guard<std::mutex> lk(_mutex);
114 return _queue.size();
115 }
116
117 //----------------------------------------------------------------------
120 //----------------------------------------------------------------------
121 bool PushBack(const _ValueType & value)
122 {
123 bool rc = false;
124 std::lock_guard<std::mutex> lk(_mutex);
125 if ((! _maxLength) ||
126 (_queue.size() < _maxLength)) {
127 _queue.push_back(value);
128 _signalled = true;
129 _cv.notify_all();
130 rc = true;
131 }
132 return(rc);
133 }
134
135 //----------------------------------------------------------------------
138 //----------------------------------------------------------------------
139 bool PushBack(_ValueType && value)
140 {
141 bool rc = false;
142 std::lock_guard<std::mutex> lk(_mutex);
143 if ((! _maxLength) ||
144 (_queue.size() < _maxLength)) {
145 _queue.push_back(value);
146 _signalled = true;
147 _cv.notify_all();
148 rc = true;
149 }
150 return(rc);
151 }
152
153 //----------------------------------------------------------------------
158 //----------------------------------------------------------------------
159 template <typename InputIterator>
160 uint32_t PushBack(InputIterator firstIter, InputIterator lastIter)
161 {
162 uint32_t rc = 0;
163 if (firstIter != lastIter) {
164 std::lock_guard<std::mutex> lk(_mutex);
165 if ((! _maxLength) ||
166 (_queue.size() < _maxLength)) {
167 uint32_t oldSize = _queue.size();
168 _queue.insert(_queue.end(), firstIter, lastIter);
169 rc = _queue.size() - oldSize;
170 if (rc) {
171 _signalled = true;
172 _cv.notify_all();
173 }
174 }
175 }
176 return(rc);
177 }
178
179 //----------------------------------------------------------------------
182 //----------------------------------------------------------------------
183 bool PushFront(const _ValueType & value)
184 {
185 bool rc = false;
186 std::lock_guard<std::mutex> lk(_mutex);
187 if ((! _maxLength) ||
188 (_queue.size() < _maxLength)) {
189 _queue.push_front(value);
190 _signalled = true;
191 _cv.notify_all();
192 rc = true;
193 }
194 return(rc);
195 }
196
197 //----------------------------------------------------------------------
199 //----------------------------------------------------------------------
200 template <typename InputIterator>
201 uint32_t PushFront(InputIterator firstIter, InputIterator lastIter)
202 {
203 uint32_t rc = 0;
204 if (firstIter != lastIter) {
205 std::lock_guard<std::mutex> lk(_mutex);
206 if ((! _maxLength) ||
207 (_queue.size() < _maxLength)) {
208 uint32_t oldSize = _queue.size();
209 _queue.insert(_queue.begin(), firstIter, lastIter);
210 rc = _queue.size() - oldSize;
211 if (rc) {
212 _signalled = true;
213 _cv.notify_all();
214 }
215 }
216 }
217 return rc;
218 }
219
220 //----------------------------------------------------------------------
222 //----------------------------------------------------------------------
224 {
225 _signalled = true;
226 _cv.notify_one();
227 }
228
229 //----------------------------------------------------------------------
231 //----------------------------------------------------------------------
233 {
234 Lock();
235 _cv.wait(_lock, [&] { return _signalled.load(); });
236 _signalled = false;
237 Unlock();
238 return true;
239 }
240
241 //----------------------------------------------------------------------
245 //----------------------------------------------------------------------
246 template<class Rep, class Period>
247 bool ConditionTimedWait(const std::chrono::duration<Rep,Period> & timeToWait)
248 {
249 bool rc = false;
250 Lock();
251 if (_cv.wait_for(_lock, timeToWait,
252 [&] { return _signalled.load(); })) {
253 rc = true;
254 }
255 _signalled = false;
256 Unlock();
257 return(rc);
258 }
259
260 //----------------------------------------------------------------------
263 //----------------------------------------------------------------------
264 bool PopFront(_ValueType & value)
265 {
266 bool rc = false;
267 std::lock_guard<std::mutex> lk(_mutex);
268 if (! _queue.empty()) {
269 if (std::is_move_assignable<_ValueType>::value) {
270 value = std::move(_queue.front());
271 }
272 else {
273 value = _queue.front();
274 }
275 _queue.pop_front();
276 rc = true;
277 }
278 return(rc);
279 }
280
281 //----------------------------------------------------------------------
284 //----------------------------------------------------------------------
285 bool PopBack(_ValueType & value)
286 {
287 bool rc = false;
288 std::lock_guard<std::mutex> lk(_mutex);
289 if (! _queue.empty()) {
290 if (std::is_move_assignable<_ValueType>::value) {
291 value = std::move(_queue.back());
292 }
293 else {
294 value = _queue.back();
295 }
296 _queue.pop_back();
297 rc = true;
298 }
299 return(rc);
300 }
301
302 //----------------------------------------------------------------------
305 //----------------------------------------------------------------------
307 {
308 bool rc = false;
309 Lock();
310 _cv.wait(_lock, [&] { return (! _queue.empty()); });
311 rc = true;
312 Unlock();
313 return(rc);
314 }
315
316 //----------------------------------------------------------------------
319 //----------------------------------------------------------------------
320 template <class Rep, class Period>
321 bool TimedWaitForNotEmpty(const std::chrono::duration<Rep, Period> & timeToWait)
322 {
323 bool rc = false;
324 Lock();
325 if (! _queue.empty()) {
326 rc = true;
327 }
328 else {
329 if (_cv.wait_for(_lock, timeToWait,
330 [&] { return _signalled.load(); })) {
331 rc = (! _queue.empty());
332 }
333 }
334 _signalled = false;
335 Unlock();
336 return(rc);
337 }
338
339 //----------------------------------------------------------------------
341 //----------------------------------------------------------------------
342 bool Empty()
343 {
344 return(_queue.empty());
345 }
346
347 //----------------------------------------------------------------------
349 //----------------------------------------------------------------------
350 void RandomShuffle()
351 {
352 std::lock_guard<std::mutex> lk(_mutex);
353 random_shuffle(_queue.begin(), _queue.end());
354 return;
355 }
356
357 //----------------------------------------------------------------------
362 //----------------------------------------------------------------------
363 uint32_t Copy(std::deque<_ValueType> & c)
364 {
365 uint32_t rc = 0;
366 if (! c.empty())
367 c.clear();
368
369 std::lock_guard<std::mutex> lk(_mutex);
370 typename std::deque<_ValueType>::iterator iter = _queue.begin();
371 for ( ; iter != _queue.end(); ++iter) {
372 c.push_back(*iter);
373 ++rc;
374 }
375 return(rc);
376 }
377
378 //----------------------------------------------------------------------
385 //----------------------------------------------------------------------
386 uint32_t Swap(std::deque<_ValueType> & c)
387 {
388 std::lock_guard<std::mutex> lk(_mutex);
389 if (! _queue.empty()) {
390 _queue.swap(c);
391 _queue.clear();
392 }
393 return(c.size());
394 }
395
396 protected:
397 uint32_t _maxLength;
398 std::deque<_ValueType> _queue;
399 mutable std::mutex _mutex;
400 std::atomic<bool> _signalled;
401 std::unique_lock<std::mutex> _lock;
402 std::condition_variable _cv;
403
404 //----------------------------------------------------------------------
406 //----------------------------------------------------------------------
407 void Lock()
408 {
409 _lock.lock();
410 return;
411 }
412
413 //----------------------------------------------------------------------
415 //----------------------------------------------------------------------
416 void Unlock()
417 {
418 _lock.unlock();
419 return;
420 }
421
422 };
423
424
425 } // namespace Thread
426
427} // namespace Dwm
428
429#endif // _DWMTHREADQUEUE_HH_
430
431//---------------------------- emacs settings -----------------------------
432// Local Variables:
433// mode: C++
434// tab-width: 2
435// indent-tabs-mode: nil
436// c-basic-offset: 2
437// End:
438//-------------------------------------------------------------------------
This template provides inter-thread first-in first-out (FIFO) queueing.
Definition DwmThreadQueue.hh:68
uint32_t PushBack(InputIterator firstIter, InputIterator lastIter)
Inserts the values from firstIter to lastIter on the back of the queue.
Definition DwmThreadQueue.hh:160
std::deque< _ValueType >::size_type Length() const
Returns the current length of the queue.
Definition DwmThreadQueue.hh:111
uint32_t Swap(std::deque< _ValueType > &c)
This member is a simple optimization for fetching the contents of the queue.
Definition DwmThreadQueue.hh:386
bool Empty()
Returns true if the queue is empty, else returns false.
Definition DwmThreadQueue.hh:342
uint32_t Copy(std::deque< _ValueType > &c)
Copies the contents of the queue to c.
Definition DwmThreadQueue.hh:363
uint32_t MaxLength(uint32_t maxLength)
Sets and returns the max length of the queue.
Definition DwmThreadQueue.hh:102
bool ConditionTimedWait(const std::chrono::duration< Rep, Period > &timeToWait)
Waits for the condition variable to be signalled or broadcasted for timeToWait to pass.
Definition DwmThreadQueue.hh:247
bool PushBack(_ValueType &&value)
Inserts value on the back of the queue.
Definition DwmThreadQueue.hh:139
bool PopBack(_ValueType &value)
Pops the entry from the back of the queue and stores it in value.
Definition DwmThreadQueue.hh:285
bool WaitForNotEmpty()
Blocks the calling thread until the queue contains at least one entry.
Definition DwmThreadQueue.hh:306
bool ConditionWait()
Waits for the condition variable to be signalled or broadcasted.
Definition DwmThreadQueue.hh:232
uint32_t MaxLength() const
Returns the max length of the queue.
Definition DwmThreadQueue.hh:93
~Queue()
Destructor.
Definition DwmThreadQueue.hh:83
bool PushBack(const _ValueType &value)
Inserts value on the back of the queue.
Definition DwmThreadQueue.hh:121
bool PopFront(_ValueType &value)
Pops the entry from the front of the queue and stores it in value.
Definition DwmThreadQueue.hh:264
bool PushFront(const _ValueType &value)
Inserts value on the front of the queue.
Definition DwmThreadQueue.hh:183
void ConditionSignal()
Unblocks at least one thread waiting on the condition variable.
Definition DwmThreadQueue.hh:223
Queue()
Constructor.
Definition DwmThreadQueue.hh:73
bool TimedWaitForNotEmpty(const std::chrono::duration< Rep, Period > &timeToWait)
Waits timeToWait for the queue to be non-empty.
Definition DwmThreadQueue.hh:321