// 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(); virtual ~SynchronizedQueue(); void setMaxLength(int maxLength); int getMaxLength(); 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); void waitForItem(double timeout); void cancelWaitForItem(); void clear(); private: void throwInvalidStateIfEmpty() throw(InvalidState); T frontAndPopUnsynchronized(); epics::pvData::Mutex mutex; epicsEvent event; int maxLength; }; template SynchronizedQueue::SynchronizedQueue() : std::queue(), mutex(), event(), maxLength(Unlimited) { } template SynchronizedQueue::~SynchronizedQueue() { event.signal(); } template int SynchronizedQueue::getMaxLength() { return maxLength; } template void SynchronizedQueue::setMaxLength(int maxLength) { epics::pvData::Lock lock(mutex); this->maxLength = maxLength; } 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(); 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(); } } waitForItem(timeout); return frontAndPop(); } template void SynchronizedQueue::pop() { epics::pvData::Lock lock(mutex); if (!std::queue::empty()) { std::queue::pop(); } } template void SynchronizedQueue::push(const T& t) { epics::pvData::Lock lock(mutex); if (maxLength > 0) { int nPop = std::queue::size()-maxLength+1; for (int i = 0; i < nPop; i++) { std::queue::pop(); } } std::queue::push(t); event.signal(); } template void SynchronizedQueue::waitForItem(double timeout) { event.wait(timeout); } template void SynchronizedQueue::cancelWaitForItem() { event.signal(); } template void SynchronizedQueue::clear() { epics::pvData::Lock lock(mutex); while (!std::queue::empty()) { std::queue::pop(); } event.signal(); } #endif