2 #ifndef artdaq_core_Core_ConcurrentQueue_hh
3 #define artdaq_core_Core_ConcurrentQueue_hh
14 #include <condition_variable>
16 #include <type_traits>
32 typedef std::chrono::duration<double> seconds;
59 typedef size_t MemoryType;
68 typedef char TrueType;
69 struct FalseType { TrueType _[2]; };
71 template <MemoryType(T:: *)() const>
75 static TrueType test(TestConst<&C::memoryUsed> *);
77 static FalseType test(...);
80 static const bool value = (
sizeof(test<T>(0)) ==
sizeof(TrueType));
85 memoryUsage(
const std::pair<T, size_t> & t)
87 MemoryType usage(0UL);
89 usage = t.first.memoryUsed();
97 typename std::enable_if<hasMemoryUsed<T>::value, MemoryType>::type
98 memoryUsage(
const T & t)
100 MemoryType usage(0UL);
102 usage = t.memoryUsed();
109 template <
typename T>
110 typename std::enable_if < !hasMemoryUsed<T>::value, MemoryType >::type
111 memoryUsage(
const T & t)
112 {
return sizeof(t); }
119 typedef void ReturnType;
122 typedef std::list<T> SequenceType;
123 typedef typename SequenceType::size_type SizeType;
126 virtual const char * what()
const throw() {
127 return "Cannot add item to a full queue";
134 SequenceType & elements,
136 detail::MemoryType
const & itemSize,
137 detail::MemoryType & used,
138 std::condition_variable & nonempty
140 elements.push_back(item);
143 nonempty.notify_one();
146 static ReturnType doEnq
149 SequenceType & elements,
152 detail::MemoryType & used,
153 detail::MemoryType & memory,
154 size_t & elementsDropped,
155 std::condition_variable & nonempty
157 detail::MemoryType itemSize = detail::memoryUsage(item);
158 if (size >= capacity || used + itemSize > memory) {
163 doInsert(item, elements, size, itemSize, used, nonempty);
169 typename FailIfFull<T>::QueueIsFull FailIfFull<T>::queueIsFull {};
173 typedef std::pair<T, size_t> ValueType;
174 typedef std::list<T> SequenceType;
175 typedef typename SequenceType::size_type SizeType;
176 typedef SizeType ReturnType;
181 SequenceType & elements,
183 detail::MemoryType
const & itemSize,
184 detail::MemoryType & used,
185 std::condition_variable & nonempty
187 elements.push_back(item);
190 nonempty.notify_one();
193 static ReturnType doEnq
196 SequenceType & elements,
199 detail::MemoryType & used,
200 detail::MemoryType & memory,
201 size_t & elementsDropped,
202 std::condition_variable & nonempty
204 SizeType elementsRemoved(0);
205 detail::MemoryType itemSize = detail::memoryUsage(item);
206 while ((size == capacity || used + itemSize > memory) && !elements.empty()) {
209 holder.splice(holder.begin(), elements, elements.begin());
212 used -= detail::memoryUsage(holder.front());
215 if (size < capacity && used + itemSize <= memory)
218 doInsert(item, elements, size, itemSize, used, nonempty);
224 elementsDropped += elementsRemoved;
225 return elementsRemoved;
232 typedef std::pair<T, size_t> ValueType;
233 typedef std::list<T> SequenceType;
234 typedef typename SequenceType::size_type SizeType;
235 typedef SizeType ReturnType;
240 SequenceType & elements,
242 detail::MemoryType
const & itemSize,
243 detail::MemoryType & used,
244 std::condition_variable & nonempty
246 elements.push_back(item);
249 nonempty.notify_one();
252 static ReturnType doEnq
255 SequenceType & elements,
258 detail::MemoryType & used,
259 detail::MemoryType & memory,
260 size_t & elementsDropped,
261 std::condition_variable & nonempty
263 detail::MemoryType itemSize = detail::memoryUsage(item);
264 if (size < capacity && used + itemSize <= memory) {
265 doInsert(item, elements, size, itemSize, used, nonempty);
277 template <
class T,
class EnqPolicy = FailIfFull<T> >
280 typedef typename EnqPolicy::ValueType ValueType;
281 typedef typename EnqPolicy::SequenceType SequenceType;
282 typedef typename SequenceType::size_type SizeType;
290 SizeType maxSize = std::numeric_limits<SizeType>::max(),
291 detail::MemoryType maxMemory = std::numeric_limits<detail::MemoryType>::max()
314 typename EnqPolicy::ReturnType
enqNowait(T
const & item);
373 SizeType
size()
const;
391 detail::MemoryType
used()
const;
397 detail::MemoryType
memory()
const;
421 typedef std::lock_guard<std::mutex> LockType;
422 typedef std::unique_lock<std::mutex> WaitLockType;
424 mutable std::mutex protectElements_;
425 mutable std::condition_variable queueNotEmpty_;
426 mutable std::condition_variable queueNotFull_;
428 SequenceType elements_;
438 detail::MemoryType memory_;
439 detail::MemoryType used_;
440 size_t elementsDropped_;
452 bool insertIfPossible(T
const & item);
462 bool removeHeadIfPossible(ValueType & item);
471 void removeHead(ValueType & item);
473 void assignItem(T & item,
const T & element);
474 void assignItem(std::pair<T, size_t> & item,
const T & element);
493 template <
class T,
class EnqPolicy>
497 detail::MemoryType maxMemory
508 template <
class T,
class EnqPolicy>
511 LockType lock(protectElements_);
515 elementsDropped_ = 0;
518 template <
class T,
class EnqPolicy>
519 typename EnqPolicy::ReturnType
522 LockType lock(protectElements_);
523 return EnqPolicy::doEnq
524 (item, elements_, size_, capacity_, used_, memory_,
525 elementsDropped_, queueNotEmpty_);
528 template <
class T,
class EnqPolicy>
532 WaitLockType lock(protectElements_);
533 while (isFull()) { queueNotFull_.wait(lock); }
534 EnqPolicy::doInsert(item, elements_, size_,
535 detail::memoryUsage(item), used_, queueNotEmpty_);
538 template <
class T,
class EnqPolicy>
543 seconds
const & waitTime
546 WaitLockType lock(protectElements_);
548 queueNotFull_.wait_for(lock, waitTime);
550 return insertIfPossible(item);
553 template <
class T,
class EnqPolicy>
557 LockType lock(protectElements_);
558 return removeHeadIfPossible(item);
561 template <
class T,
class EnqPolicy>
565 WaitLockType lock(protectElements_);
566 while (size_ == 0) { queueNotEmpty_.wait(lock); }
570 template <
class T,
class EnqPolicy>
575 seconds
const & waitTime
578 WaitLockType lock(protectElements_);
580 queueNotEmpty_.wait_for(lock, waitTime);
582 return removeHeadIfPossible(item);
585 template <
class T,
class EnqPolicy>
593 template <
class T,
class EnqPolicy>
597 LockType lock(protectElements_);
601 template <
class T,
class EnqPolicy>
602 typename ConcurrentQueue<T, EnqPolicy>::SizeType
609 template <
class T,
class EnqPolicy>
610 typename ConcurrentQueue<T, EnqPolicy>::SizeType
617 template <
class T,
class EnqPolicy>
621 LockType lock(protectElements_);
622 bool isEmpty = (size_ == 0);
623 if (isEmpty) { capacity_ = newcapacity; }
627 template <
class T,
class EnqPolicy>
635 template <
class T,
class EnqPolicy>
643 template <
class T,
class EnqPolicy>
647 LockType lock(protectElements_);
648 bool isEmpty = (size_ == 0);
649 if (isEmpty) { memory_ = newmemory; }
653 template <
class T,
class EnqPolicy>
654 typename ConcurrentQueue<T, EnqPolicy>::SizeType
657 LockType lock(protectElements_);
658 SizeType clearedEvents = size_;
659 elementsDropped_ += size_;
663 return clearedEvents;
666 template <
class T,
class EnqPolicy>
670 LockType lock(protectElements_);
671 elementsDropped_ += n;
678 template <
class T,
class EnqPolicy>
687 EnqPolicy::doInsert(item, elements_, size_,
688 detail::memoryUsage(item), used_, queueNotEmpty_);
693 template <
class T,
class EnqPolicy>
695 ConcurrentQueue<T, EnqPolicy>::removeHeadIfPossible(ValueType & item)
697 if (size_ == 0) {
return false; }
702 template <
class T,
class EnqPolicy>
704 ConcurrentQueue<T, EnqPolicy>::removeHead(ValueType & item)
708 holder.splice(holder.begin(), elements_, elements_.begin());
711 queueNotFull_.notify_one();
712 assignItem(item, holder.front());
713 used_ -= detail::memoryUsage(item);
716 template <
class T,
class EnqPolicy>
718 ConcurrentQueue<T, EnqPolicy>::assignItem(T & item,
const T & element)
723 template <
class T,
class EnqPolicy>
725 ConcurrentQueue<T, EnqPolicy>::assignItem(std::pair<T, size_t> & item,
const T & element)
727 item.first = element;
728 item.second = elementsDropped_;
729 elementsDropped_ = 0;
732 template <
class T,
class EnqPolicy>
734 ConcurrentQueue<T, EnqPolicy>::isFull()
const
736 if (size_ >= capacity_ || used_ >= memory_) {
return true; }
bool enqTimedWait(T const &p, seconds const &)
bool setMemory(detail::MemoryType n)
void addExternallyDroppedEvents(SizeType)
ConcurrentQueue(SizeType maxSize=std::numeric_limits< SizeType >::max(), detail::MemoryType maxMemory=std::numeric_limits< detail::MemoryType >::max())
detail::MemoryType memory() const
bool deqNowait(ValueType &)
EnqPolicy::ReturnType enqNowait(T const &item)
bool deqTimedWait(ValueType &, seconds const &)
SizeType capacity() const
void deqWait(ValueType &)
bool setCapacity(SizeType n)
detail::MemoryType used() const