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