You.i Engine
YiConcurrentDeque.h
Go to the documentation of this file.
1 // © You i Labs Inc. 2000-2020. All rights reserved.
2 #ifndef _YI_CONCURRENT_DEQUE_H_
3 #define _YI_CONCURRENT_DEQUE_H_
4 
5 #include "framework/YiPredef.h"
6 
7 #include <condition_variable>
8 #include <deque>
9 #include <mutex>
10 
21 template<typename YI_DATA>
23 {
24 public:
27  , m_stopWaiting(false)
28  , m_EmptyCondition(YI_SYNCHRONIZATION_OBJECT_INIT_VALUE)
29  , m_AvailableCondition(YI_SYNCHRONIZATION_OBJECT_INIT_VALUE)
30  {
31  }
32 
35  , m_stopWaiting(false)
36  , m_EmptyCondition(YI_SYNCHRONIZATION_OBJECT_INIT_VALUE)
37  , m_AvailableCondition(YI_SYNCHRONIZATION_OBJECT_INIT_VALUE)
38  {
39  std::unique_lock<std::mutex> autoMutex(other.m_mutex);
40  m_deque = other.m_deque;
41  }
42 
44  {
45  std::unique_lock<std::mutex> autoLhsMutex(m_mutex);
46  std::unique_lock<std::mutex> autoRhsMutex(rhs.m_mutex);
47  m_deque = rhs.m_deque;
48  return *this;
49  }
50 
54  void PushFront(const YI_DATA &rData)
55  {
56  std::unique_lock<std::mutex> autoMutex(m_mutex);
57 
58  m_deque.push_front(rData);
59 
60  m_AvailableCondition.notify_one();
61  }
62 
66  void PushBack(const YI_DATA &rData)
67  {
68  std::unique_lock<std::mutex> autoMutex(m_mutex);
69 
70  m_deque.push_back(rData);
71 
72  m_AvailableCondition.notify_one();
73  }
74 
78  void WaitEmpty()
79  {
80  std::unique_lock<std::mutex> autoMutex(m_mutex);
81  while (!m_deque.empty()) // protection against 'spurious wake-ups'
82  {
83  m_EmptyCondition.wait(autoMutex);
84  }
85  }
86 
90  bool Empty() const
91  {
92  std::unique_lock<std::mutex> autoMutex(m_mutex);
93  return m_deque.empty();
94  }
95 
100  bool TryPopFront(YI_DATA &rValue)
101  {
102  bool successfulLock = false;
103 
104  if (m_mutex.try_lock())
105  {
106  if (!m_deque.empty())
107  {
108  rValue = m_deque.front();
109  m_deque.pop_front();
110 
111  successfulLock = true;
112 
113  if (m_deque.empty())
114  {
115  m_EmptyCondition.notify_all();
116  }
117  }
118 
119  m_mutex.unlock();
120  }
121 
122  return successfulLock;
123  }
124 
128  bool TryPopBack(YI_DATA &rValue)
129  {
130  bool successfulLock = false;
131 
132  if (m_mutex.try_lock())
133  {
134  if (!m_deque.empty())
135  {
136  rValue = m_deque.back();
137  m_deque.pop_back();
138 
139  successfulLock = true;
140 
141  if (m_deque.empty())
142  {
143  m_EmptyCondition.notify_all();
144  }
145  }
146 
147  m_mutex.unlock();
148  }
149 
150  return successfulLock;
151  }
152 
158  bool WaitAndPopFront(YI_DATA &rValue)
159  {
160  bool ret = false;
161 
162  std::unique_lock<std::mutex> autoMutex(m_mutex);
163 
164  while (m_deque.empty() && !m_stopWaiting)
165  {
166  m_AvailableCondition.wait(autoMutex);
167  }
168 
169  m_stopWaiting = false;
170 
171  if (!m_deque.empty())
172  {
173  rValue = m_deque.front();
174  m_deque.pop_front();
175 
176  if (m_deque.empty())
177  {
178  m_EmptyCondition.notify_all();
179  }
180 
181  ret = true;
182  }
183 
184  return ret;
185  }
186 
193  bool WaitAndPopFront(YI_DATA &rValue, uint64_t timeoutMs)
194  {
195  bool ret = false;
196 
197  std::unique_lock<std::mutex> autoMutex(m_mutex);
198 
199  if (!m_stopWaiting && m_deque.empty())
200  {
201  m_AvailableCondition.wait_for(autoMutex, std::chrono::milliseconds(timeoutMs));
202  }
203 
204  m_stopWaiting = false;
205 
206  if (!m_deque.empty())
207  {
208  rValue = m_deque.front();
209  m_deque.pop_front();
210 
211  if (m_deque.empty())
212  {
213  m_EmptyCondition.notify_all();
214  }
215 
216  ret = true;
217  }
218 
219  return ret;
220  }
221 
225  bool WaitAndPopBack(YI_DATA &rValue)
226  {
227  bool ret = false;
228 
229  std::unique_lock<std::mutex> autoMutex(m_mutex);
230 
231  while (m_deque.empty() && !m_stopWaiting)
232  {
233  m_AvailableCondition.wait(autoMutex);
234  }
235 
236  m_stopWaiting = false;
237 
238  if (!m_deque.empty())
239  {
240  rValue = m_deque.back();
241  m_deque.pop_back();
242 
243  if (m_deque.empty())
244  {
245  m_EmptyCondition.notify_all();
246  }
247 
248  ret = true;
249  }
250 
251  return ret;
252  }
253 
260  void StopWaiting()
261  {
262  std::unique_lock<std::mutex> autoMutex(m_mutex);
263 
264  m_stopWaiting = true;
265  m_AvailableCondition.notify_one();
266  }
267 
271  size_t GetSize() const
272  {
273  std::unique_lock<std::mutex> autoMutex(m_mutex);
274  return m_deque.size();
275  }
276 
277 private:
278  std::deque<YI_DATA> m_deque;
279  mutable std::mutex m_mutex;
280 
281  bool m_stopWaiting;
282  std::condition_variable m_EmptyCondition;
283  std::condition_variable m_AvailableCondition;
284 };
285 
288 #endif // _YI_CONCURRENT_DEQUE_H_
void PushBack(const YI_DATA &rData)
Definition: YiConcurrentDeque.h:66
bool TryPopBack(YI_DATA &rValue)
Definition: YiConcurrentDeque.h:128
#define YI_SYNCHRONIZATION_OBJECT_INIT_VALUE
Definition: YiPredef.h:49
CYIConcurrentDeque(const CYIConcurrentDeque< YI_DATA > &other)
Definition: YiConcurrentDeque.h:33
CYIConcurrentDeque()
Definition: YiConcurrentDeque.h:25
void StopWaiting()
Definition: YiConcurrentDeque.h:260
bool WaitAndPopFront(YI_DATA &rValue)
Definition: YiConcurrentDeque.h:158
bool WaitAndPopFront(YI_DATA &rValue, uint64_t timeoutMs)
Definition: YiConcurrentDeque.h:193
void PushFront(const YI_DATA &rData)
Definition: YiConcurrentDeque.h:54
void WaitEmpty()
Definition: YiConcurrentDeque.h:78
bool TryPopFront(YI_DATA &rValue)
Definition: YiConcurrentDeque.h:100
CYIConcurrentDeque & operator=(const CYIConcurrentDeque< YI_DATA > &rhs)
Definition: YiConcurrentDeque.h:43
bool Empty() const
Definition: YiConcurrentDeque.h:90
A simple, thread safe deque.
Definition: YiConcurrentDeque.h:22
bool WaitAndPopBack(YI_DATA &rValue)
Definition: YiConcurrentDeque.h:225
size_t GetSize() const
Definition: YiConcurrentDeque.h:271