2 #ifndef artdaq_core_Core_ConcurrentQueue_hh
3 #define artdaq_core_Core_ConcurrentQueue_hh
15 #include <condition_variable>
17 #include <type_traits>
33 typedef std::chrono::duration<double> seconds;
60 typedef size_t MemoryType;
69 typedef char TrueType;
70 struct FalseType { TrueType _[2]; };
72 template <MemoryType(T:: *)() const>
76 static TrueType test(TestConst<&C::memoryUsed> *);
78 static FalseType test(...);
81 static const bool value = (
sizeof(test<T>(0)) ==
sizeof(TrueType));
86 memoryUsage(
const std::pair<T, size_t> & t)
88 MemoryType usage(0UL);
90 usage = t.first.memoryUsed();
98 typename std::enable_if<hasMemoryUsed<T>::value, MemoryType>::type
99 memoryUsage(
const T & t)
101 MemoryType usage(0UL);
103 usage = t.memoryUsed();
110 template <
typename T>
111 typename std::enable_if < !hasMemoryUsed<T>::value, MemoryType >::type
112 memoryUsage(
const T & t)
113 {
return sizeof(t); }
120 typedef bool ReturnType;
123 typedef std::list<T> SequenceType;
124 typedef typename SequenceType::size_type SizeType;
127 virtual const char * what()
const throw() {
128 return "Cannot add item to a full queue";
135 SequenceType & elements,
137 detail::MemoryType
const & itemSize,
138 detail::MemoryType & used,
139 std::condition_variable & nonempty
141 elements.push_back(item);
144 nonempty.notify_one();
147 static ReturnType doEnq
150 SequenceType & elements,
153 detail::MemoryType & used,
154 detail::MemoryType & memory,
155 size_t & elementsDropped,
156 std::condition_variable & nonempty
158 detail::MemoryType itemSize = detail::memoryUsage(item);
159 if (size >= capacity || used + itemSize > memory) {
164 doInsert(item, elements, size, itemSize, used, nonempty);
171 typename FailIfFull<T>::QueueIsFull FailIfFull<T>::queueIsFull {};
175 typedef std::pair<T, size_t> ValueType;
176 typedef std::list<T> SequenceType;
177 typedef typename SequenceType::size_type SizeType;
178 typedef SizeType ReturnType;
183 SequenceType & elements,
185 detail::MemoryType
const & itemSize,
186 detail::MemoryType & used,
187 std::condition_variable & nonempty
189 elements.push_back(item);
192 nonempty.notify_one();
195 static ReturnType doEnq
198 SequenceType & elements,
201 detail::MemoryType & used,
202 detail::MemoryType & memory,
203 size_t & elementsDropped,
204 std::condition_variable & nonempty
206 SizeType elementsRemoved(0);
207 detail::MemoryType itemSize = detail::memoryUsage(item);
208 while ((size == capacity || used + itemSize > memory) && !elements.empty()) {
211 holder.splice(holder.begin(), elements, elements.begin());
214 used -= detail::memoryUsage(holder.front());
217 if (size < capacity && used + itemSize <= memory)
220 doInsert(item, elements, size, itemSize, used, nonempty);
226 elementsDropped += elementsRemoved;
227 return elementsRemoved;
234 typedef std::pair<T, size_t> ValueType;
235 typedef std::list<T> SequenceType;
236 typedef typename SequenceType::size_type SizeType;
237 typedef SizeType ReturnType;
242 SequenceType & elements,
244 detail::MemoryType
const & itemSize,
245 detail::MemoryType & used,
246 std::condition_variable & nonempty
248 elements.push_back(item);
251 nonempty.notify_one();
254 static ReturnType doEnq
257 SequenceType & elements,
260 detail::MemoryType & used,
261 detail::MemoryType & memory,
262 size_t & elementsDropped,
263 std::condition_variable & nonempty
265 detail::MemoryType itemSize = detail::memoryUsage(item);
266 if (size < capacity && used + itemSize <= memory) {
267 doInsert(item, elements, size, itemSize, used, nonempty);
279 template <
class T,
class EnqPolicy = FailIfFull<T> >
282 typedef typename EnqPolicy::ValueType ValueType;
283 typedef typename EnqPolicy::SequenceType SequenceType;
284 typedef typename SequenceType::size_type SizeType;
292 SizeType maxSize = std::numeric_limits<SizeType>::max(),
293 detail::MemoryType maxMemory = std::numeric_limits<detail::MemoryType>::max()
316 typename EnqPolicy::ReturnType
enqNowait(T
const & item);
375 SizeType
size()
const;
393 detail::MemoryType
used()
const;
399 detail::MemoryType
memory()
const;
430 readyTime_ = std::chrono::steady_clock::now();
437 std::chrono::steady_clock::time_point
getReadyTime() {
return readyTime_; }
440 typedef std::lock_guard<std::mutex> LockType;
441 typedef std::unique_lock<std::mutex> WaitLockType;
443 mutable std::mutex protectElements_;
444 mutable std::condition_variable queueNotEmpty_;
445 mutable std::condition_variable queueNotFull_;
447 std::chrono::steady_clock::time_point readyTime_;
449 SequenceType elements_;
459 detail::MemoryType memory_;
460 detail::MemoryType used_;
461 size_t elementsDropped_;
473 bool insertIfPossible(T
const & item);
483 bool removeHeadIfPossible(ValueType & item);
492 void removeHead(ValueType & item);
494 void assignItem(T & item,
const T & element);
495 void assignItem(std::pair<T, size_t> & item,
const T & element);
514 template <
class T,
class EnqPolicy>
518 detail::MemoryType maxMemory
521 readyTime_(std::chrono::steady_clock::now()),
531 template <
class T,
class EnqPolicy>
534 LockType lock(protectElements_);
538 elementsDropped_ = 0;
544 template <
class T,
class EnqPolicy>
547 TRACE( 12,
"ConcurrentQueue<T,EnqPolicy>::enqNowait enter size=%zu capacity=%zu used=%zu memory=%zu", size_, capacity_, used_, memory_ );
548 LockType lock(protectElements_);
549 auto retval = EnqPolicy::doEnq(item, elements_, size_, capacity_, used_, memory_,
550 elementsDropped_, queueNotEmpty_);
551 TRACE( 12,
"ConcurrentQueue<T,EnqPolicy>::enqNowait returning %zu", (SizeType)retval );
555 template <
class T,
class EnqPolicy>
558 TRACE( 12,
"ConcurrentQueue<T,EnqPolicy>::enqWait enter" );
559 WaitLockType lock(protectElements_);
560 while (isFull()) { queueNotFull_.wait(lock); }
561 EnqPolicy::doInsert(item, elements_, size_,
562 detail::memoryUsage(item), used_, queueNotEmpty_);
563 TRACE( 12,
"ConcurrentQueue<T,EnqPolicy>::enqWait returning" );
566 template <
class T,
class EnqPolicy>
569 TRACE( 12,
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait enter with waitTime=%ld ms size=%zu capacity=%zu used=%zu memory=%zu"
570 , std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count(), size_, capacity_, used_, memory_ );
571 WaitLockType lock(protectElements_);
573 queueNotFull_.wait_for(lock, waitTime);
575 bool retval=insertIfPossible(item);
576 TRACE( 12,
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait returning %d", retval );
583 template <
class T,
class EnqPolicy>
586 TRACE( 12,
"ConcurrentQueue<T, EnqPolicy>::deqNowait enter" );
587 LockType lock(protectElements_);
588 bool retval = removeHeadIfPossible(item);
589 TRACE( 12,
"ConcurrentQueue<T, EnqPolicy>::deqNowait returning %d", retval );
593 template <
class T,
class EnqPolicy>
596 TRACE( 12,
"ConcurrentQueue<T, EnqPolicy>::deqWait enter" );
597 WaitLockType lock(protectElements_);
598 while (size_ == 0) { queueNotEmpty_.wait(lock); }
600 TRACE( 12,
"ConcurrentQueue<T, EnqPolicy>::deqWait returning" );
603 template <
class T,
class EnqPolicy>
606 TRACE( 12,
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait enter with waitTime=%ld ms size=%zu"
607 , std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count(), size_ );
608 WaitLockType lock(protectElements_);
610 queueNotEmpty_.wait_for(lock, waitTime);
612 bool retval=removeHeadIfPossible(item);
613 TRACE( 12,
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait returning %d size=%zu", retval, size_ );
619 template <
class T,
class EnqPolicy>
627 template <
class T,
class EnqPolicy>
631 LockType lock(protectElements_);
635 template <
class T,
class EnqPolicy>
636 typename ConcurrentQueue<T, EnqPolicy>::SizeType
643 template <
class T,
class EnqPolicy>
644 typename ConcurrentQueue<T, EnqPolicy>::SizeType
651 template <
class T,
class EnqPolicy>
655 LockType lock(protectElements_);
656 bool isEmpty = (size_ == 0);
657 if (isEmpty) { capacity_ = newcapacity; }
661 template <
class T,
class EnqPolicy>
669 template <
class T,
class EnqPolicy>
677 template <
class T,
class EnqPolicy>
681 LockType lock(protectElements_);
682 bool isEmpty = (size_ == 0);
683 if (isEmpty) { memory_ = newmemory; }
687 template <
class T,
class EnqPolicy>
688 typename ConcurrentQueue<T, EnqPolicy>::SizeType
691 LockType lock(protectElements_);
692 SizeType clearedEvents = size_;
693 elementsDropped_ += size_;
697 return clearedEvents;
700 template <
class T,
class EnqPolicy>
704 LockType lock(protectElements_);
705 elementsDropped_ += n;
712 template <
class T,
class EnqPolicy>
721 EnqPolicy::doInsert(item, elements_, size_,
722 detail::memoryUsage(item), used_, queueNotEmpty_);
727 template <
class T,
class EnqPolicy>
729 ConcurrentQueue<T, EnqPolicy>::removeHeadIfPossible(ValueType & item)
731 if (size_ == 0) {
return false; }
736 template <
class T,
class EnqPolicy>
738 ConcurrentQueue<T, EnqPolicy>::removeHead(ValueType & item)
742 holder.splice(holder.begin(), elements_, elements_.begin());
745 queueNotFull_.notify_one();
746 assignItem(item, holder.front());
747 used_ -= detail::memoryUsage(item);
750 template <
class T,
class EnqPolicy>
752 ConcurrentQueue<T, EnqPolicy>::assignItem(T & item,
const T & element)
757 template <
class T,
class EnqPolicy>
759 ConcurrentQueue<T, EnqPolicy>::assignItem(std::pair<T, size_t> & item,
const T & element)
761 item.first = element;
762 item.second = elementsDropped_;
763 elementsDropped_ = 0;
766 template <
class T,
class EnqPolicy>
768 ConcurrentQueue<T, EnqPolicy>::isFull()
const
770 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())
std::chrono::steady_clock::time_point getReadyTime()
detail::MemoryType memory() const
void setReaderIsReady(bool rdy=true)
bool deqNowait(ValueType &)
EnqPolicy::ReturnType enqNowait(T const &item)
bool queueReaderIsReady()
bool deqTimedWait(ValueType &, seconds const &)
SizeType capacity() const
void deqWait(ValueType &)
bool setCapacity(SizeType n)
detail::MemoryType used() const