diff options
author | Jesse Gilles <jgilles@multitech.com> | 2015-04-20 16:49:52 -0500 |
---|---|---|
committer | Jesse Gilles <jgilles@multitech.com> | 2015-04-20 16:49:52 -0500 |
commit | 17b117e73df71925d73ee026b4f54aa1867ce0a5 (patch) | |
tree | 382610c8e598a77a961c5ceb32b9b614ed00e757 /include/mts/MTS_Queue.h | |
download | libmts-17b117e73df71925d73ee026b4f54aa1867ce0a5.tar.gz libmts-17b117e73df71925d73ee026b4f54aa1867ce0a5.tar.bz2 libmts-17b117e73df71925d73ee026b4f54aa1867ce0a5.zip |
initial commit
Diffstat (limited to 'include/mts/MTS_Queue.h')
-rw-r--r-- | include/mts/MTS_Queue.h | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/include/mts/MTS_Queue.h b/include/mts/MTS_Queue.h new file mode 100644 index 0000000..aa59e51 --- /dev/null +++ b/include/mts/MTS_Queue.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/*! \file MTS_Queue.h + \brief A queue + \date 15JUN11 + \author Sean Godinez + + A thread-safe queue with condition signaling + */ +#ifndef _MTS_QUEUE_H_ +#define _MTS_QUEUE_H_ + +#include <mts/MTS_NonCopyable.h> +#include <mts/MTS_AutoPtr.h> +#include <mts/MTS_Lock.h> +#include <mts/MTS_Logger.h> +#include <mts/MTS_Stdint.h> +#include <queue> +#include <cassert> + +namespace MTS { + + //! A queue + /*! + A thread-safe, blocking, template queue that signals when it is not empty, and when it is not full. + + \sa AutoPtr, Lock + */ + template<class T> class Queue : public NonCopyable { + + public: + explicit Queue(uint32_t capacity = UINT32_MAX); //!< Constructs the queue + ~Queue(); //!< Destructs the queue + + bool empty() const; //!< Returns true if queue is empty + bool full() const; //!< Returns true if queue is full + uint32_t size() const; //!< Returns the number of elements in the queue + uint32_t capacity() const; //!< Returns the maximum capacity of the queue + + void push(const T& object); //!< Pushes an object on the queue (BLOCKS IF FULL) + void pop(T& object); //!< Pops an object off the queue (BLOCKS IF EMPTY) + + bool offer(const T& object, uint32_t waitMillis); + bool poll(T& object, uint32_t waitMillis); + bool peek(T& object, uint32_t waitMillis); + + private: + const uint32_t m_iMaxSize; + std::queue<T> m_qContainer; + AutoPtr<Lock> m_apLock; + AutoPtr<Condition> m_apNotEmpty; + AutoPtr<Condition> m_apNotFull; + }; + + template<class T> Queue<T>::Queue(uint32_t capacity) + : m_iMaxSize(capacity) { + m_apLock.reset(new Lock()); + m_apNotEmpty.reset(m_apLock->createCondition()); + m_apNotFull.reset(m_apLock->createCondition()); + } + + template<class T> Queue<T>::~Queue() { + m_apNotFull.reset(); + m_apNotEmpty.reset(); + m_apLock.reset(); + } + + template<class T> bool Queue<T>::empty() const { + bool result = false; + m_apLock->lock(); + result = m_qContainer.empty(); + m_apLock->unlock(); + return result; + } + + template<class T> bool Queue<T>::full() const { + bool result = false; + m_apLock->lock(); + result = (m_qContainer.size() >= m_iMaxSize); + m_apLock->unlock(); + return result; + } + + template<class T> uint32_t Queue<T>::size() const { + uint32_t result = 0; + m_apLock->lock(); + result = static_cast<uint32_t>(m_qContainer.size()); + m_apLock->unlock(); + return result; + } + + template<class T> uint32_t Queue<T>::capacity() const { + return m_iMaxSize; + } + + template<class T> void Queue<T>::push(const T& object) { + // Block forever until there is room on the queue + m_apLock->lock(); + try { + while (m_qContainer.size() >= m_iMaxSize) { + m_apNotFull->wait(); + } + m_qContainer.push(object); + m_apNotEmpty->signal(); + } catch (...) { + printWarning("Queue| failed to push object"); + assert(false); + } + m_apLock->unlock(); + } + + template<class T> void Queue<T>::pop(T& object) { + //Block on not-empty condition if empty + m_apLock->lock(); + while (m_qContainer.empty()) { + m_apNotEmpty->wait(); + } + object = m_qContainer.front(); + m_qContainer.pop(); + m_apNotFull->signal(); + m_apLock->unlock(); + } + + //! Attempts to push an object onto the queue within the given milliseconds + /*! + \param object an object to push onto the queue + \param waitMillis the amount of milliseonds to wait if the queue is full + \return Returns true if the object was pushed onto the queue, false otherwise + \sa push() + */ + template<class T> bool Queue<T>::offer(const T& object, + uint32_t waitMillis) { + bool result = false; + m_apLock->lock(); + try { + if (waitMillis > 0 && m_qContainer.size() >= m_iMaxSize) { + m_apNotFull->wait(waitMillis); + } + if (m_qContainer.size() < m_iMaxSize) { + m_qContainer.push(object); + m_apNotEmpty->signal(); + result = true; + } + } catch (...) { + printWarning("Queue| failed to offer object"); + assert(false); + } + m_apLock->unlock(); + return result; + } + + //! Attempts to pop an object from the queue within the given milliseconds + /*! + \param object if successful, a reference to the object that was popped + \param waitMillis the amount of milliseonds to wait if the queue is empty + \return Returns true if an object was popped from the queue, false otherwise + \sa pop(), peek() + */ + template<class T> bool Queue<T>::poll(T& object, uint32_t waitMillis) { + bool result = false; + m_apLock->lock(); + if (waitMillis > 0 && m_qContainer.empty()) { + m_apNotEmpty->wait(waitMillis); + } + if (!m_qContainer.empty()) { + object = m_qContainer.front(); + m_qContainer.pop(); + m_apNotFull->signal(); + result = true; + } + m_apLock->unlock(); + return result; + } + + //! Attempts to view the top of the queue within the given milliseconds + /*! + \param object if successful, a reference to the object that is at the head of the queue + \param waitMillis the amount of milliseonds to wait if the queue is empty + \return Returns true if there is an object in the queue, false otherwise + \sa pop(), poll() + */ + template<class T> bool Queue<T>::peek(T& object, uint32_t waitMillis) { + bool result = false; + m_apLock->lock(); + if (waitMillis > 0 && m_qContainer.empty()) { + m_apNotEmpty->wait(waitMillis); + } + if (!m_qContainer.empty()) { + object = m_qContainer.front(); + result = true; + } + m_apLock->unlock(); + return result; + } +} + +#endif |