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);
270 std::condition_variable& nonempty)
272 elements.push_back(item);
275 nonempty.notify_one();
297 size_t& elementsDropped,
298 std::condition_variable& nonempty)
302 while ((size == capacity || used + itemSize > memory) && !elements.empty())
306 holder.splice(holder.begin(), elements, elements.begin());
312 if (size < capacity && used + itemSize <= memory)
315 doInsert(item, elements, size, itemSize, used, nonempty);
322 elementsDropped += elementsRemoved;
323 return elementsRemoved;
354 std::condition_variable& nonempty)
356 elements.push_back(item);
359 nonempty.notify_one();
381 size_t& elementsDropped,
382 std::condition_variable& nonempty)
385 if (size < capacity && used + itemSize <= memory)
387 doInsert(item, elements, size, itemSize, used, nonempty);
398 template<
class T,
class EnqPolicy = FailIfFull<T>>
413 SizeType maxSize = std::numeric_limits<SizeType>::max(),
440 typename EnqPolicy::ReturnType
enqNowait(T
const& item);
593 readyTime_ = std::chrono::steady_clock::now();
601 std::chrono::steady_clock::time_point
getReadyTime()
const {
return readyTime_; }
604 typedef std::lock_guard<std::mutex> LockType;
605 typedef std::unique_lock<std::mutex> WaitLockType;
607 mutable std::mutex protectElements_;
608 mutable std::condition_variable queueNotEmpty_;
609 mutable std::condition_variable queueNotFull_;
611 std::chrono::steady_clock::time_point readyTime_;
612 bool readerReady_{
false};
625 size_t elementsDropped_{0};
637 bool insertIfPossible(T
const& item);
652 bool removeHeadIfPossible(
ValueType& item);
667 void assignItem(T& item,
const T& element);
669 void assignItem(std::pair<T, size_t>& item,
const T& element);
682 ConcurrentQueue& operator=(ConcurrentQueue<T, EnqPolicy>
const&) =
delete;
691 template<
class T,
class EnqPolicy>
696 , readyTime_(std::chrono::steady_clock::now())
703 template<
class T,
class EnqPolicy>
706 LockType lock(protectElements_);
710 elementsDropped_ = 0;
715 template<
class T,
class EnqPolicy>
718 TLOG(12,
"ConcurrentQueue") <<
"enqNowait enter size=" << size_ <<
" capacity=" << capacity_ <<
" used=" << used_ <<
" memory=" << memory_;
719 LockType lock(protectElements_);
720 auto retval = EnqPolicy::doEnq(item, elements_, size_, capacity_, used_, memory_,
721 elementsDropped_, queueNotEmpty_);
722 TLOG(12,
"ConcurrentQueue") <<
"enqNowait returning " << retval;
726 template<
class T,
class EnqPolicy>
729 TLOG(13,
"ConcurrentQueue") <<
"enqWait enter";
730 WaitLockType lock(protectElements_);
731 while (isFull()) { queueNotFull_.wait(lock); }
732 EnqPolicy::doInsert(item, elements_, size_,
734 TLOG(13,
"ConcurrentQueue") <<
"enqWait returning";
737 template<
class T,
class EnqPolicy>
740 TLOG(14,
"ConcurrentQueue") <<
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait enter with waitTime=" << std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count() <<
" ms size=" << size_
741 <<
" capacity=" << capacity_ <<
" used=" << used_ <<
" memory=" << memory_;
742 WaitLockType lock(protectElements_);
745 queueNotFull_.wait_for(lock, waitTime);
747 bool retval = insertIfPossible(item);
748 TLOG(14,
"ConcurrentQueue") <<
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait returning " << retval;
754 template<
class T,
class EnqPolicy>
757 TLOG(15,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqNowait enter";
758 LockType lock(protectElements_);
759 bool retval = removeHeadIfPossible(item);
760 TLOG(15,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqNowait returning " << retval;
764 template<
class T,
class EnqPolicy>
767 TLOG(16,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqWait enter";
768 WaitLockType lock(protectElements_);
769 while (size_ == 0) { queueNotEmpty_.wait(lock); }
771 TLOG(16,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqWait returning";
774 template<
class T,
class EnqPolicy>
777 TLOG(17,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait enter with waitTime=" << std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count() <<
" ms size=" << size_;
778 WaitLockType lock(protectElements_);
781 queueNotEmpty_.wait_for(lock, waitTime);
783 bool retval = removeHeadIfPossible(item);
784 TLOG(17,
"ConcurrentQueue") <<
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait returning " << retval <<
" size=" << size_;
788 template<
class T,
class EnqPolicy>
795 template<
class T,
class EnqPolicy>
798 LockType lock(protectElements_);
802 template<
class T,
class EnqPolicy>
810 template<
class T,
class EnqPolicy>
818 template<
class T,
class EnqPolicy>
821 LockType lock(protectElements_);
822 bool isEmpty = (size_ == 0);
823 if (isEmpty) { capacity_ = newcapacity; }
827 template<
class T,
class EnqPolicy>
835 template<
class T,
class EnqPolicy>
843 template<
class T,
class EnqPolicy>
846 LockType lock(protectElements_);
847 bool isEmpty = (size_ == 0);
848 if (isEmpty) { memory_ = maxMemory; }
852 template<
class T,
class EnqPolicy>
856 LockType lock(protectElements_);
858 elementsDropped_ += size_;
862 return clearedEvents;
865 template<
class T,
class EnqPolicy>
868 LockType lock(protectElements_);
869 elementsDropped_ += dropped;
876 template<
class T,
class EnqPolicy>
886 EnqPolicy::doInsert(item, elements_, size_,
892 template<
class T,
class EnqPolicy>
893 bool ConcurrentQueue<T, EnqPolicy>::removeHeadIfPossible(ValueType& item)
895 if (size_ == 0) {
return false; }
900 template<
class T,
class EnqPolicy>
901 void ConcurrentQueue<T, EnqPolicy>::removeHead(ValueType& item)
905 holder.splice(holder.begin(), elements_, elements_.begin());
908 queueNotFull_.notify_one();
909 assignItem(item, holder.front());
913 template<
class T,
class EnqPolicy>
914 void ConcurrentQueue<T, EnqPolicy>::assignItem(T& item,
const T& element)
919 template<
class T,
class EnqPolicy>
920 void ConcurrentQueue<T, EnqPolicy>::assignItem(std::pair<T, size_t>& item,
const T& element)
922 item.first = element;
923 item.second = elementsDropped_;
924 elementsDropped_ = 0;
927 template<
class T,
class EnqPolicy>
928 bool ConcurrentQueue<T, EnqPolicy>::isFull()
const
930 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.
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.