// Copyright information and license terms for this software can be // found in the file LICENSE that is included with the distribution #ifndef SYNCHRONIZED_QUEUE_H #define SYNCHRONIZED_QUEUE_H #include #include "epicsEvent.h" #include "pv/pvData.h" #include "InvalidState.h" template class SynchronizedQueue : public std::queue { public: static const int Unlimited = -1; SynchronizedQueue(int maxLength=Unlimited); virtual ~SynchronizedQueue(); void setMaxLength(int maxLength); int getMaxLength(); bool isFull(); T back() throw(InvalidState); T front() throw(InvalidState); T frontAndPop() throw(InvalidState); T frontAndPop(double timeout) throw(InvalidState); void pop(); void push(const T& t) throw(InvalidState); void pushIfNotFull(const T& t); void waitForItemPushed(double timeout); void waitForItemPopped(double timeout); void waitForItemPoppedIfFull(double timeout); void cancelWaitForItemPushed(); void cancelWaitForItemPopped(); void clear(); private: void throwInvalidStateIfEmpty() throw(InvalidState); T frontAndPopUnsynchronized(); epics::pvData::Mutex mutex; epicsEvent itemPushedEvent; epicsEvent itemPoppedEvent; int maxLength; }; template SynchronizedQueue::SynchronizedQueue(int maxLength_) : std::queue(), mutex(), itemPushedEvent(), itemPoppedEvent(), maxLength(maxLength_) { } template SynchronizedQueue::~SynchronizedQueue() { itemPushedEvent.signal(); itemPoppedEvent.signal(); } template int SynchronizedQueue::getMaxLength() { return maxLength; } template void SynchronizedQueue::setMaxLength(int maxLength) { epics::pvData::Lock lock(mutex); this->maxLength = maxLength; } template bool SynchronizedQueue::isFull() { int size = std::queue::size(); if (maxLength > 0 && size >= maxLength) { return true; } return false; } template void SynchronizedQueue::throwInvalidStateIfEmpty() throw(InvalidState) { if (std::queue::empty()) { throw InvalidState("Invalid state: queue is empty."); } } template T SynchronizedQueue::back() throw(InvalidState) { epics::pvData::Lock lock(mutex); throwInvalidStateIfEmpty(); return std::queue::back(); } template T SynchronizedQueue::front() throw(InvalidState) { epics::pvData::Lock lock(mutex); throwInvalidStateIfEmpty(); return std::queue::front(); } template T SynchronizedQueue::frontAndPopUnsynchronized() { T t = std::queue::front(); std::queue::pop(); itemPoppedEvent.signal(); return t; } template T SynchronizedQueue::frontAndPop() throw(InvalidState) { epics::pvData::Lock lock(mutex); throwInvalidStateIfEmpty(); return frontAndPopUnsynchronized(); } template T SynchronizedQueue::frontAndPop(double timeout) throw(InvalidState) { { epics::pvData::Lock lock(mutex); if (!std::queue::empty()) { return frontAndPopUnsynchronized(); } } waitForItemPushed(timeout); return frontAndPop(); } template void SynchronizedQueue::pop() { epics::pvData::Lock lock(mutex); if (!std::queue::empty()) { std::queue::pop(); itemPoppedEvent.signal(); } } template void SynchronizedQueue::push(const T& t) throw(InvalidState) { epics::pvData::Lock lock(mutex); int size = std::queue::size(); if (maxLength > 0 && size >= maxLength) { // We are full, throw exception throw InvalidState("Invalid state: queue is full."); return; } std::queue::push(t); itemPushedEvent.signal(); } template void SynchronizedQueue::pushIfNotFull(const T& t) { epics::pvData::Lock lock(mutex); int size = std::queue::size(); if (maxLength > 0 && size >= maxLength) { // We are full, ignore push request return; } std::queue::push(t); itemPushedEvent.signal(); } template void SynchronizedQueue::waitForItemPushed(double timeout) { itemPushedEvent.wait(timeout); } template void SynchronizedQueue::waitForItemPopped(double timeout) { itemPoppedEvent.wait(timeout); } template void SynchronizedQueue::waitForItemPoppedIfFull(double timeout) { // Wait for pop only if we are full int size = std::queue::size(); if (maxLength > 0 && size >= maxLength) { itemPoppedEvent.wait(timeout); } } template void SynchronizedQueue::cancelWaitForItemPushed() { itemPushedEvent.signal(); } template void SynchronizedQueue::cancelWaitForItemPopped() { itemPoppedEvent.signal(); } template void SynchronizedQueue::clear() { epics::pvData::Lock lock(mutex); while (!std::queue::empty()) { std::queue::pop(); itemPoppedEvent.signal(); } } #endif