1 #ifndef _DETHREADSAFERINGBUFFER_HPP 2 #define _DETHREADSAFERINGBUFFER_HPP 3 /*------------------------------------------------------------------------- 4 * drawElements C++ Base Library 5 * ----------------------------- 6 * 7 * Copyright 2014 The Android Open Source Project 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Thread-safe ring buffer template. 24 *//*--------------------------------------------------------------------*/ 25 26 #include "deDefs.hpp" 27 #include "deMutex.hpp" 28 #include "deSemaphore.hpp" 29 30 #include <vector> 31 32 namespace de 33 { 34 35 void ThreadSafeRingBuffer_selfTest(void); 36 37 /** Thread-safe ring buffer template. */ 38 template <typename T> 39 class ThreadSafeRingBuffer 40 { 41 public: 42 ThreadSafeRingBuffer(size_t size); ~ThreadSafeRingBuffer(void)43 ~ThreadSafeRingBuffer(void) 44 { 45 } 46 47 void pushFront(const T &elem); 48 bool tryPushFront(const T &elem); 49 T popBack(void); 50 bool tryPopBack(T &dst); 51 52 protected: 53 void pushFrontInternal(const T &elem); 54 T popBackInternal(void); 55 56 const size_t m_size; 57 std::vector<T> m_elements; 58 59 size_t m_front; 60 size_t m_back; 61 62 Mutex m_writeMutex; 63 Mutex m_readMutex; 64 65 Semaphore m_fill; 66 Semaphore m_empty; 67 }; 68 69 // ThreadSafeRingBuffer implementation. 70 71 template <typename T> ThreadSafeRingBuffer(size_t size)72ThreadSafeRingBuffer<T>::ThreadSafeRingBuffer(size_t size) 73 : m_size(size + 1) 74 , m_elements(m_size) 75 , m_front(0) 76 , m_back(0) 77 , m_fill(0) 78 , m_empty((int)size) 79 { 80 // Semaphores currently only support INT_MAX 81 DE_ASSERT(size > 0 && size < 0x7fffffff); 82 } 83 84 template <typename T> pushFrontInternal(const T & elem)85inline void ThreadSafeRingBuffer<T>::pushFrontInternal(const T &elem) 86 { 87 m_elements[m_front] = elem; 88 m_front = (m_front + 1) % m_size; 89 } 90 91 template <typename T> popBackInternal()92inline T ThreadSafeRingBuffer<T>::popBackInternal() 93 { 94 const size_t ndx = m_back; 95 m_back = (m_back + 1) % m_size; 96 return m_elements[ndx]; 97 } 98 99 template <typename T> pushFront(const T & elem)100void ThreadSafeRingBuffer<T>::pushFront(const T &elem) 101 { 102 m_writeMutex.lock(); 103 m_empty.decrement(); 104 pushFrontInternal(elem); 105 m_fill.increment(); 106 m_writeMutex.unlock(); 107 } 108 109 template <typename T> tryPushFront(const T & elem)110bool ThreadSafeRingBuffer<T>::tryPushFront(const T &elem) 111 { 112 if (!m_writeMutex.tryLock()) 113 return false; 114 115 const bool success = m_empty.tryDecrement(); 116 117 if (success) 118 { 119 pushFrontInternal(elem); 120 m_fill.increment(); 121 } 122 123 m_writeMutex.unlock(); 124 return success; 125 } 126 127 template <typename T> popBack()128T ThreadSafeRingBuffer<T>::popBack() 129 { 130 m_readMutex.lock(); 131 m_fill.decrement(); 132 T elem = popBackInternal(); 133 m_empty.increment(); 134 m_readMutex.unlock(); 135 return elem; 136 } 137 138 template <typename T> tryPopBack(T & dst)139bool ThreadSafeRingBuffer<T>::tryPopBack(T &dst) 140 { 141 if (!m_readMutex.tryLock()) 142 return false; 143 144 bool success = m_fill.tryDecrement(); 145 146 if (success) 147 { 148 dst = popBackInternal(); 149 m_empty.increment(); 150 } 151 152 m_readMutex.unlock(); 153 154 return success; 155 } 156 157 } // namespace de 158 159 #endif // _DETHREADSAFERINGBUFFER_HPP 160