1 #ifndef artdaq_core_Core_ConcurrentQueue_hh
2 #define artdaq_core_Core_ConcurrentQueue_hh
14 #include <condition_variable>
16 #include <type_traits>
58 typedef std::chrono::duration<double>
seconds;
70 typedef char TrueType;
77 template<MemoryType (T::*)() const>
81 static TrueType test(TestConst<&C::memoryUsed>*)
87 static FalseType test(...)
98 static const bool value = (
sizeof(test<T>(
nullptr)) ==
sizeof(TrueType));
114 usage = t.first.memoryUsed();
128 typename std::enable_if<hasMemoryUsed<T>::value,
MemoryType>::type
134 usage = t.memoryUsed();
148 typename std::enable_if<!hasMemoryUsed<T>::value,
MemoryType>::type
177 virtual const char*
what()
const throw()
179 return "Cannot add item to a full queue";
198 std::condition_variable& nonempty)
200 elements.push_back(item);
203 nonempty.notify_one();
226 size_t& elementsDropped,
227 std::condition_variable& nonempty)
230 if (size >= capacity || used + itemSize > memory)
237 doInsert(item, elements, size, itemSize, used, nonempty);
273 std::condition_variable& nonempty)
275 elements.push_back(item);
278 nonempty.notify_one();
300 size_t& elementsDropped,
301 std::condition_variable& nonempty)
305 while ((size == capacity || used + itemSize > memory) && !elements.empty())
309 holder.splice(holder.begin(), elements, elements.begin());
315 if (size < capacity && used + itemSize <= memory)
318 doInsert(item, elements, size, itemSize, used, nonempty);
325 elementsDropped += elementsRemoved;
326 return elementsRemoved;
357 std::condition_variable& nonempty)
359 elements.push_back(item);
362 nonempty.notify_one();
384 size_t& elementsDropped,
385 std::condition_variable& nonempty)
388 if (size < capacity && used + itemSize <= memory)
390 doInsert(item, elements, size, itemSize, used, nonempty);
401 template<
class T,
class EnqPolicy = FailIfFull<T>>
416 SizeType maxSize = std::numeric_limits<SizeType>::max(),
443 typename EnqPolicy::ReturnType
enqNowait(T
const& item);
596 readyTime_ = std::chrono::steady_clock::now();
604 std::chrono::steady_clock::time_point
getReadyTime()
const {
return readyTime_; }
607 typedef std::lock_guard<std::mutex> LockType;
608 typedef std::unique_lock<std::mutex> WaitLockType;
610 mutable std::mutex protectElements_;
611 mutable std::condition_variable queueNotEmpty_;
612 mutable std::condition_variable queueNotFull_;
614 std::chrono::steady_clock::time_point readyTime_;
628 size_t elementsDropped_;
640 bool insertIfPossible(T
const& item);
655 bool removeHeadIfPossible(
ValueType& item);
670 void assignItem(T& item,
const T& element);
672 void assignItem(std::pair<T, size_t>& item,
const T& element);
692 template<
class T,
class EnqPolicy>
697 , readyTime_(std::chrono::steady_clock::now())
698 , readerReady_(false)
704 , elementsDropped_(0)
707 template<
class T,
class EnqPolicy>
710 LockType lock(protectElements_);
714 elementsDropped_ = 0;
719 template<
class T,
class EnqPolicy>
722 TLOG(12,
"ConcurrentQueue") <<
"enqNowait enter size=" << size_ <<
" capacity=" << capacity_ <<
" used=" << used_ <<
" memory=" << memory_;
723 LockType lock(protectElements_);
724 auto retval = EnqPolicy::doEnq(item, elements_, size_, capacity_, used_, memory_,
725 elementsDropped_, queueNotEmpty_);
726 TLOG(12,
"ConcurrentQueue") <<
"enqNowait returning " << retval;
730 template<
class T,
class EnqPolicy>
733 TLOG(13,
"ConcurrentQueue") <<
"enqWait enter";
734 WaitLockType lock(protectElements_);
735 while (isFull()) { queueNotFull_.wait(lock); }
736 EnqPolicy::doInsert(item, elements_, size_,
738 TLOG(13,
"ConcurrentQueue") <<
"enqWait returning";
741 template<
class T,
class EnqPolicy>
744 TLOG(14,
"ConcurrentQueue") <<
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait enter with waitTime=" << std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count() <<
" ms size=" << size_
745 <<
" capacity=" << capacity_ <<
" used=" << used_ <<
" memory=" << memory_;
746 WaitLockType lock(protectElements_);
749 queueNotFull_.wait_for(lock, waitTime);
751 bool retval = insertIfPossible(item);
752 TLOG(14,
"ConcurrentQueue") <<
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait returning " << retval;
758 template<
class T,
class EnqPolicy>
761 TLOG(15,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqNowait enter";
762 LockType lock(protectElements_);
763 bool retval = removeHeadIfPossible(item);
764 TLOG(15,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqNowait returning " << retval;
768 template<
class T,
class EnqPolicy>
771 TLOG(16,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqWait enter";
772 WaitLockType lock(protectElements_);
773 while (size_ == 0) { queueNotEmpty_.wait(lock); }
775 TLOG(16,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqWait returning";
778 template<
class T,
class EnqPolicy>
781 TLOG(17,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait enter with waitTime=" << std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count() <<
" ms size=" << size_;
782 WaitLockType lock(protectElements_);
785 queueNotEmpty_.wait_for(lock, waitTime);
787 bool retval = removeHeadIfPossible(item);
788 TLOG(17,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait returning " << retval <<
" size=" << size_;
792 template<
class T,
class EnqPolicy>
799 template<
class T,
class EnqPolicy>
802 LockType lock(protectElements_);
806 template<
class T,
class EnqPolicy>
814 template<
class T,
class EnqPolicy>
822 template<
class T,
class EnqPolicy>
825 LockType lock(protectElements_);
826 bool isEmpty = (size_ == 0);
827 if (isEmpty) { capacity_ = newcapacity; }
831 template<
class T,
class EnqPolicy>
839 template<
class T,
class EnqPolicy>
847 template<
class T,
class EnqPolicy>
850 LockType lock(protectElements_);
851 bool isEmpty = (size_ == 0);
852 if (isEmpty) { memory_ = newmemory; }
856 template<
class T,
class EnqPolicy>
860 LockType lock(protectElements_);
862 elementsDropped_ += size_;
866 return clearedEvents;
869 template<
class T,
class EnqPolicy>
872 LockType lock(protectElements_);
873 elementsDropped_ += n;
880 template<
class T,
class EnqPolicy>
890 EnqPolicy::doInsert(item, elements_, size_,
896 template<
class T,
class EnqPolicy>
897 bool ConcurrentQueue<T, EnqPolicy>::removeHeadIfPossible(ValueType& item)
899 if (size_ == 0) {
return false; }
904 template<
class T,
class EnqPolicy>
905 void ConcurrentQueue<T, EnqPolicy>::removeHead(ValueType& item)
909 holder.splice(holder.begin(), elements_, elements_.begin());
912 queueNotFull_.notify_one();
913 assignItem(item, holder.front());
917 template<
class T,
class EnqPolicy>
918 void ConcurrentQueue<T, EnqPolicy>::assignItem(T& item,
const T& element)
923 template<
class T,
class EnqPolicy>
924 void ConcurrentQueue<T, EnqPolicy>::assignItem(std::pair<T, size_t>& item,
const T& element)
926 item.first = element;
927 item.second = elementsDropped_;
928 elementsDropped_ = 0;
931 template<
class T,
class EnqPolicy>
932 bool ConcurrentQueue<T, EnqPolicy>::isFull()
const
934 if (size_ >= capacity_ || used_ >= memory_) {
return true; }
std::chrono::steady_clock::time_point getReadyTime() const
Gets the time at which the queue became ready.
std::list< T > SequenceType
Type of sequences of items.
T ValueType
Type of values stored in queue.
static ReturnType doEnq(T const &item, SequenceType &elements, SizeType &size, SizeType &capacity, detail::MemoryType &used, detail::MemoryType &memory, size_t &elementsDropped, std::condition_variable &nonempty)
Attempts to enqueue an item.
SizeType clear()
Remove all items from the queue. This changes the size to zero but does not change the capacity...
detail::MemoryType used() const
Return the memory in bytes used by items in the queue.
std::pair< T, size_t > ValueType
Type of elements stored in the queue.
virtual const char * what() const
Describe exception.
detail::MemoryType memory() const
Return the memory of the queue in bytes, that is, the maximum memory the items in the queue may occup...
SequenceType::size_type SizeType
Size type of seqeuences.
MemoryType memoryUsage(const std::pair< T, size_t > &t)
Returns the memory used by an object.
std::pair< T, size_t > ValueType
Type of elements stored in the queue.
std::chrono::duration< double > seconds
EnqPolicy::SequenceType SequenceType
Type of sequence used by ConcurrentQueue.
EnqPolicy::ReturnType enqNowait(T const &item)
Add a copy if item to the queue, according to the rules determined by the EnqPolicy.
SequenceType::size_type SizeType
Size type of seqeuences.
static void doInsert(T const &item, SequenceType &elements, SizeType &size, detail::MemoryType const &itemSize, detail::MemoryType &used, std::condition_variable &nonempty)
Inserts element into the ConcurrentQueue.
std::list< T > SequenceType
Type of sequences of items.
bool setCapacity(SizeType capacity)
SizeType ReturnType
Type returned by doEnq.
SequenceType::size_type SizeType
Size type of seqeuences.
ConcurrentQueue policy to throw an exception when the queue is full.
size_t MemoryType
Basic unit of data storage and pointer types.
Exception thrown by FailIfFull policy when an enqueue operation is attempted on a full queue...
ConcurrentQueue policy to discard oldest elements when the queue is full.
static const bool value
Use SFINAE to figure out if the class used to instantiate the ConcurrentQueue template has a method m...
ConcurrentQueue policy to discard new elements when the queue is full.
static void doInsert(T const &item, SequenceType &elements, SizeType &size, detail::MemoryType const &itemSize, detail::MemoryType &used, std::condition_variable &nonempty)
Inserts element into the ConcurrentQueue.
bool deqNowait(ValueType &item)
Assign the value at the head of the queue to item and then remove the head of the queue...
bool setMemory(detail::MemoryType maxMemory)
Reset the memory usage in bytes of the queue. A value of 0 disabled the memory check. This can only be done if the queue is empty.
SizeType ReturnType
Type returned by doEnq.
artdaq::FailIfFull::QueueIsFull queueIsFull
Instance of QueueIsFull exception.
ConcurrentQueue(SizeType maxSize=std::numeric_limits< SizeType >::max(), detail::MemoryType maxMemory=std::numeric_limits< detail::MemoryType >::max())
ConcurrentQueue is always bounded. By default, the bound is absurdly large.
static ReturnType doEnq(T const &item, SequenceType &elements, SizeType &size, SizeType &capacity, detail::MemoryType &used, detail::MemoryType &memory, size_t &elementsDropped, std::condition_variable &nonempty)
Attempts to enqueue an item.
void enqWait(T const &item)
Add a copy of item to the queue.
bool deqTimedWait(ValueType &item, detail::seconds const &wait)
Assign the value at the head of the queue to item and then remove the head of the queue...
bool enqTimedWait(T const &item, detail::seconds const &wait)
Add a copy of item to the queue, waiting for the queue to be non-full.
std::list< T > SequenceType
Type of seqeuences of values.
void addExternallyDroppedEvents(SizeType dropped)
Adds the passed count to the counter of dropped events.
static void doInsert(T const &item, SequenceType &elements, SizeType &size, detail::MemoryType const &itemSize, detail::MemoryType &used, std::condition_variable &nonempty)
Inserts element into the ConcurrentQueue.
void deqWait(ValueType &item)
Assign the value of the head of the queue to item and then remove the head of the queue...
SizeType capacity() const
Return the capacity of the queue, that is, the maximum number of items it can contain.
void setReaderIsReady(bool rdy=true)
Set the ready flag for the reader.
EnqPolicy::ValueType ValueType
Type of values stored in ConcurrentQueue.
SequenceType::size_type SizeType
Type for indexes in sequence.
static ReturnType doEnq(T const &item, SequenceType &elements, SizeType &size, SizeType &capacity, detail::MemoryType &used, detail::MemoryType &memory, size_t &elementsDropped, std::condition_variable &nonempty)
Attempts to enqueue an item.
bool queueReaderIsReady() const
Is the reader connected and ready for items to appear on the queue?
bool ReturnType
Type returned by doEnq.