File indexing completed on 2024-04-28 04:52:04
0001 /* 0002 SPDX-FileCopyrightText: 2015 Meltytech LLC 0003 SPDX-FileCopyrightText: 2015 Brian Matherly <code@brianmatherly.com> 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #pragma once 0009 0010 #include <QList> 0011 #include <QMutex> 0012 #include <QMutexLocker> 0013 #include <QWaitCondition> 0014 0015 /*! 0016 \class DataQueue 0017 \brief The DataQueue provides a thread safe container for passing data between 0018 objects. 0019 0020 threadsafe 0021 0022 DataQueue provides a limited size container for passing data between objects. 0023 One object can add data to the queue by calling push() while another object 0024 can remove items from the queue by calling pop(). 0025 0026 DataQueue provides configurable behavior for handling overflows. It can 0027 discard the oldest, discard the newest or block the object calling push() 0028 until room has been freed in the queue by another object calling pop(). 0029 0030 DataQueue is threadsafe and is therefore most appropriate when passing data 0031 between objects operating in different thread contexts. 0032 */ 0033 0034 template <class T> class DataQueue 0035 { 0036 public: 0037 //! Overflow behavior modes. 0038 typedef enum { 0039 OverflowModeDiscardOldest = 0, //!< Discard oldest items 0040 OverflowModeDiscardNewest, //!< Discard newest items 0041 OverflowModeWait //!< Wait for space to be free 0042 } OverflowMode; 0043 0044 /*! 0045 Constructs a DataQueue. 0046 0047 The \a size will be the maximum queue size and the \a mode will dictate 0048 overflow behavior. 0049 */ 0050 explicit DataQueue(int maxSize, OverflowMode mode); 0051 0052 //! Destructs a DataQueue. 0053 virtual ~DataQueue(); 0054 0055 /*! 0056 Pushes an item into the queue. 0057 0058 If the queue is full and overflow mode is OverflowModeWait then this 0059 function will block until pop() is called. 0060 */ 0061 void push(const T &item); 0062 0063 /*! 0064 Pops an item from the queue. 0065 0066 If the queue is empty then this function will block. If blocking is 0067 undesired, then check the return of count() before calling pop(). 0068 */ 0069 T pop(); 0070 0071 //! Returns the number of items in the queue. 0072 int count() const; 0073 0074 private: 0075 QList<T> m_queue; 0076 int m_maxSize; 0077 OverflowMode m_mode; 0078 mutable QMutex m_mutex; 0079 QWaitCondition m_notEmptyCondition; 0080 QWaitCondition m_notFullCondition; 0081 }; 0082 0083 template <class T> 0084 DataQueue<T>::DataQueue(int maxSize, OverflowMode mode) 0085 : m_queue() 0086 , m_maxSize(maxSize) 0087 , m_mode(mode) 0088 , m_mutex() 0089 , m_notEmptyCondition() 0090 , m_notFullCondition() 0091 { 0092 } 0093 0094 template <class T> DataQueue<T>::~DataQueue() = default; 0095 0096 template <class T> void DataQueue<T>::push(const T &item) 0097 { 0098 m_mutex.lock(); 0099 if (m_queue.size() == m_maxSize) { 0100 switch (m_mode) { 0101 case OverflowModeDiscardOldest: 0102 m_queue.removeFirst(); 0103 m_queue.append(item); 0104 break; 0105 case OverflowModeDiscardNewest: 0106 // This item is the newest so discard it and exit 0107 break; 0108 case OverflowModeWait: 0109 m_notFullCondition.wait(&m_mutex); 0110 m_queue.append(item); 0111 break; 0112 } 0113 } else { 0114 m_queue.append(item); 0115 if (m_queue.size() == 1) { 0116 m_notEmptyCondition.wakeOne(); 0117 } 0118 } 0119 m_mutex.unlock(); 0120 } 0121 0122 template <class T> T DataQueue<T>::pop() 0123 { 0124 T retVal; 0125 m_mutex.lock(); 0126 if (m_queue.size() == 0) { 0127 m_notEmptyCondition.wait(&m_mutex); 0128 } 0129 retVal = m_queue.takeFirst(); 0130 if (m_mode == OverflowModeWait && m_queue.size() == m_maxSize - 1) { 0131 m_notFullCondition.wakeOne(); 0132 } 0133 m_mutex.unlock(); 0134 return retVal; 0135 } 0136 0137 template <class T> int DataQueue<T>::count() const 0138 { 0139 QMutexLocker locker(&m_mutex); 0140 return m_queue.size(); 0141 }