1 #ifndef artdaq_core_Core_ConcurrentQueue_hh
2 #define artdaq_core_Core_ConcurrentQueue_hh
14 #include <condition_variable>
16 #include <type_traits>
61 typedef std::chrono::duration<double>
seconds;
73 typedef char TrueType;
80 template <MemoryType(T::*)() const>
84 static TrueType test(TestConst<&C::memoryUsed>*) {
return 0; }
87 static FalseType test(...)
99 static const bool value = (
sizeof(test<T>(
nullptr)) ==
sizeof(TrueType));
108 template <
typename T>
115 usage = t.first.memoryUsed();
127 template <
typename T>
128 typename std::enable_if<hasMemoryUsed<T>::value,
MemoryType>::type
134 usage = t.memoryUsed();
146 template <
typename T>
147 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";
199 std::condition_variable& nonempty
202 elements.push_back(item);
205 nonempty.notify_one();
229 size_t& elementsDropped,
230 std::condition_variable& nonempty
234 if (size >= capacity || used + itemSize > memory)
241 doInsert(item, elements, size, itemSize, used, nonempty);
247 template <
typename T>
278 std::condition_variable& nonempty
281 elements.push_back(item);
284 nonempty.notify_one();
307 size_t& elementsDropped,
308 std::condition_variable& nonempty
313 while ((size == capacity || used + itemSize > memory) && !elements.empty())
317 holder.splice(holder.begin(), elements, elements.begin());
323 if (size < capacity && used + itemSize <= memory)
326 doInsert(item, elements, size, itemSize, used, nonempty);
333 elementsDropped += elementsRemoved;
334 return elementsRemoved;
366 std::condition_variable& nonempty
369 elements.push_back(item);
372 nonempty.notify_one();
395 size_t& elementsDropped,
396 std::condition_variable& nonempty
400 if (size < capacity && used + itemSize <= memory)
402 doInsert(item, elements, size, itemSize, used, nonempty);
413 template <
class T,
class EnqPolicy = FailIfFull<T>>
429 SizeType maxSize = std::numeric_limits<SizeType>::max(),
457 typename EnqPolicy::ReturnType
enqNowait(T
const& item);
610 readyTime_ = std::chrono::steady_clock::now();
618 std::chrono::steady_clock::time_point
getReadyTime()
const {
return readyTime_; }
621 typedef std::lock_guard<std::mutex> LockType;
622 typedef std::unique_lock<std::mutex> WaitLockType;
624 mutable std::mutex protectElements_;
625 mutable std::condition_variable queueNotEmpty_;
626 mutable std::condition_variable queueNotFull_;
628 std::chrono::steady_clock::time_point readyTime_;
642 size_t elementsDropped_;
654 bool insertIfPossible(T
const& item);
669 bool removeHeadIfPossible(
ValueType& item);
684 void assignItem(T& item,
const T& element);
686 void assignItem(std::pair<T, size_t>& item,
const T& element);
706 template <
class T,
class EnqPolicy>
713 , readyTime_(std::chrono::steady_clock::now())
714 , readerReady_(
false)
720 , elementsDropped_(0) {}
722 template <
class T,
class EnqPolicy>
725 LockType lock(protectElements_);
729 elementsDropped_ = 0;
735 template <
class T,
class EnqPolicy>
738 TRACE(12,
"ConcurrentQueue<T,EnqPolicy>::enqNowait enter size=%zu capacity=%zu used=%zu memory=%zu", size_, capacity_, used_, memory_);
739 LockType lock(protectElements_);
740 auto retval = EnqPolicy::doEnq(item, elements_, size_, capacity_, used_, memory_,
741 elementsDropped_, queueNotEmpty_);
742 TRACE(12,
"ConcurrentQueue<T,EnqPolicy>::enqNowait returning %zu", (
SizeType)retval);
746 template <
class T,
class EnqPolicy>
749 TRACE(12,
"ConcurrentQueue<T,EnqPolicy>::enqWait enter");
750 WaitLockType lock(protectElements_);
751 while (isFull()) { queueNotFull_.wait(lock); }
752 EnqPolicy::doInsert(item, elements_, size_,
754 TRACE(12,
"ConcurrentQueue<T,EnqPolicy>::enqWait returning");
757 template <
class T,
class EnqPolicy>
760 TRACE(12,
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait enter with waitTime=%ld ms size=%zu capacity=%zu used=%zu memory=%zu"
761 , std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count(), size_, capacity_, used_, memory_);
762 WaitLockType lock(protectElements_);
765 queueNotFull_.wait_for(lock, waitTime);
767 bool retval = insertIfPossible(item);
768 TRACE(12,
"ConcurrentQueue<T,EnqPolicy>::enqTimedWait returning %d", retval);
775 template <
class T,
class EnqPolicy>
778 TRACE(12,
"ConcurrentQueue<T, EnqPolicy>::deqNowait enter");
779 LockType lock(protectElements_);
780 bool retval = removeHeadIfPossible(item);
781 TRACE(12,
"ConcurrentQueue<T, EnqPolicy>::deqNowait returning %d", retval);
785 template <
class T,
class EnqPolicy>
788 TRACE(12,
"ConcurrentQueue<T, EnqPolicy>::deqWait enter");
789 WaitLockType lock(protectElements_);
790 while (size_ == 0) { queueNotEmpty_.wait(lock); }
792 TRACE(12,
"ConcurrentQueue<T, EnqPolicy>::deqWait returning");
795 template <
class T,
class EnqPolicy>
798 TRACE(12,
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait enter with waitTime=%ld ms size=%zu"
799 , std::chrono::duration_cast<std::chrono::milliseconds>(waitTime).count(), size_);
800 WaitLockType lock(protectElements_);
803 queueNotEmpty_.wait_for(lock, waitTime);
805 bool retval = removeHeadIfPossible(item);
806 TRACE(12,
"ConcurrentQueue<T, EnqPolicy>::deqTimedWait returning %d size=%zu", retval, size_);
811 template <
class T,
class EnqPolicy>
819 template <
class T,
class EnqPolicy>
823 LockType lock(protectElements_);
827 template <
class T,
class EnqPolicy>
835 template <
class T,
class EnqPolicy>
843 template <
class T,
class EnqPolicy>
847 LockType lock(protectElements_);
848 bool isEmpty = (size_ == 0);
849 if (isEmpty) { capacity_ = newcapacity; }
853 template <
class T,
class EnqPolicy>
861 template <
class T,
class EnqPolicy>
869 template <
class T,
class EnqPolicy>
873 LockType lock(protectElements_);
874 bool isEmpty = (size_ == 0);
875 if (isEmpty) { memory_ = newmemory; }
879 template <
class T,
class EnqPolicy>
883 LockType lock(protectElements_);
885 elementsDropped_ += size_;
889 return clearedEvents;
892 template <
class T,
class EnqPolicy>
896 LockType lock(protectElements_);
897 elementsDropped_ += n;
904 template <
class T,
class EnqPolicy>
915 EnqPolicy::doInsert(item, elements_, size_,
921 template <
class T,
class EnqPolicy>
923 ConcurrentQueue<T, EnqPolicy>::removeHeadIfPossible(ValueType& item)
925 if (size_ == 0) {
return false; }
930 template <
class T,
class EnqPolicy>
932 ConcurrentQueue<T, EnqPolicy>::removeHead(ValueType& item)
936 holder.splice(holder.begin(), elements_, elements_.begin());
939 queueNotFull_.notify_one();
940 assignItem(item, holder.front());
944 template <
class T,
class EnqPolicy>
946 ConcurrentQueue<T, EnqPolicy>::assignItem(T& item,
const T& element)
951 template <
class T,
class EnqPolicy>
953 ConcurrentQueue<T, EnqPolicy>::assignItem(std::pair<T, size_t>& item,
const T& element)
955 item.first = element;
956 item.second = elementsDropped_;
957 elementsDropped_ = 0;
960 template <
class T,
class EnqPolicy>
962 ConcurrentQueue<T, EnqPolicy>::isFull()
const
964 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.