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 void pushFront (const T& elem); 46 bool tryPushFront (const T& elem); 47 T popBack (void); 48 bool tryPopBack (T& dst); 49 50 protected: 51 void pushFrontInternal (const T& elem); 52 T popBackInternal (void); 53 54 const size_t m_size; 55 std::vector<T> m_elements; 56 57 size_t m_front; 58 size_t m_back; 59 60 Mutex m_writeMutex; 61 Mutex m_readMutex; 62 63 Semaphore m_fill; 64 Semaphore m_empty; 65 }; 66 67 // ThreadSafeRingBuffer implementation. 68 69 template <typename T> ThreadSafeRingBuffer(size_t size)70ThreadSafeRingBuffer<T>::ThreadSafeRingBuffer (size_t size) 71 : m_size (size+1) 72 , m_elements (m_size) 73 , m_front (0) 74 , m_back (0) 75 , m_fill (0) 76 , m_empty ((int)size) 77 { 78 // Semaphores currently only support INT_MAX 79 DE_ASSERT(size > 0 && size < 0x7fffffff); 80 } 81 82 template <typename T> pushFrontInternal(const T & elem)83inline void ThreadSafeRingBuffer<T>::pushFrontInternal (const T& elem) 84 { 85 m_elements[m_front] = elem; 86 m_front = (m_front + 1) % m_size; 87 } 88 89 template <typename T> popBackInternal()90inline T ThreadSafeRingBuffer<T>::popBackInternal () 91 { 92 const size_t ndx = m_back; 93 m_back = (m_back + 1) % m_size; 94 return m_elements[ndx]; 95 } 96 97 template <typename T> pushFront(const T & elem)98void ThreadSafeRingBuffer<T>::pushFront (const T& elem) 99 { 100 m_writeMutex.lock(); 101 m_empty.decrement(); 102 pushFrontInternal(elem); 103 m_fill.increment(); 104 m_writeMutex.unlock(); 105 } 106 107 template <typename T> tryPushFront(const T & elem)108bool ThreadSafeRingBuffer<T>::tryPushFront (const T& elem) 109 { 110 if (!m_writeMutex.tryLock()) 111 return false; 112 113 const bool success = m_empty.tryDecrement(); 114 115 if (success) 116 { 117 pushFrontInternal(elem); 118 m_fill.increment(); 119 } 120 121 m_writeMutex.unlock(); 122 return success; 123 } 124 125 template <typename T> popBack()126T ThreadSafeRingBuffer<T>::popBack () 127 { 128 m_readMutex.lock(); 129 m_fill.decrement(); 130 T elem = popBackInternal(); 131 m_empty.increment(); 132 m_readMutex.unlock(); 133 return elem; 134 } 135 136 template <typename T> tryPopBack(T & dst)137bool ThreadSafeRingBuffer<T>::tryPopBack (T& dst) 138 { 139 if (!m_readMutex.tryLock()) 140 return false; 141 142 bool success = m_fill.tryDecrement(); 143 144 if (success) 145 { 146 dst = popBackInternal(); 147 m_empty.increment(); 148 } 149 150 m_readMutex.unlock(); 151 152 return success; 153 } 154 155 } // de 156 157 #endif // _DETHREADSAFERINGBUFFER_HPP 158