OROCHI
 
Loading...
Searching...
No Matches
GxLockFreeQueue.h
Go to the documentation of this file.
1//===========================================================================
9//===========================================================================
10#pragma once
11
12GX_CORE_NAMESPACE_BEGIN()
13
14//===========================================================================
16//===========================================================================
17template <class T, GxAllocatorList::ALLOCATOR_TYPE ALLOCATOR>
19{
20 //-----------------------------------------------------------
22 //-----------------------------------------------------------
24public:
25 // new, delete定義
26 GX_OPERATOR_NEW_DELETE(ALLOCATOR)
27
28
29 struct Node
30 {
31 struct Node* _pNext;
33 };
34
36 //-----------------------------------------------------------
38 //-----------------------------------------------------------
40public:
43 : _pAllocatorList(nullptr)
44 , _pBuffer(nullptr)
45 , _pFree(nullptr)
46 , _pHead(nullptr)
47 , _pTail(nullptr)
48 , _queueMax(0)
49 {}
50
52 ~GxLockFreeQueue(void){ terminate(); }
53
54private:
55 // コピーコンストラクタ (コピー禁止)
56 GxLockFreeQueue(const GxLockFreeQueue&) = delete;
57 // 代入演算子 (コピー禁止)
58 GX_FORCE_INLINE const GxLockFreeQueue& operator=(const GxLockFreeQueue&) = delete;
59
61 //-----------------------------------------------------------
63 //-----------------------------------------------------------
65public:
67 b32 initialize(u32 queueMax);
69 void terminate(void);
70
72 //-----------------------------------------------------------
74 //-----------------------------------------------------------
76public:
78 b32 enqueue(const T& src);
80 b32 dequeue(T& dst);
81
83 //-----------------------------------------------------------
85 //-----------------------------------------------------------
87public:
89 b32 isEmpty(void) const;
91 u32 getCount(void) const;
92
94 //-----------------------------------------------------------
96 //-----------------------------------------------------------
98private:
99 GxAllocatorList* _pAllocatorList;
100 Node* _pBuffer;
101 volatile Node* _pFree;
102 volatile Node* _pHead;
103 volatile Node* _pTail;
104 u32 _queueMax;
105
107};
108
109//-----------------------------------------------------------
110// 初期化
113//-----------------------------------------------------------
114template<class T, GxAllocatorList::ALLOCATOR_TYPE ALLOCATOR>
116{
117 b32 ret = true;
118
119 // アロケータ設定
120 _pAllocatorList = GxAllocatorList::getAllocatorList(ALLOCATOR);
121 GX_ASSERT(_pAllocatorList != nullptr, "getAllocatorList(%d) failed!!", ALLOCATOR);
122
123 // キューバッファ個数設定 (終端判定分+1しておく)
124 _queueMax = queueMax + 1;
125
126 // キューバッファ確保
127 u32 size = sizeof(Node) * _queueMax;
128 _pBuffer = reinterpret_cast<Node*>( GX_ALLOCATE_MEMORY(_pAllocatorList, size) );
129 if( !_pBuffer )
130 {
131 GX_ERROR(false, "allocateMemory<number:%d, size:%d> failed!!", ALLOCATOR, size);
132 ret = false;
133 }
134 else
135 {
136 // 初期化 (リストの連結)
137 GX_MEMSET(_pBuffer, 0, size);
138 for (u32 i = 0; i < _queueMax - 1; ++i)
139 {
140 _pBuffer[i]._pNext = &_pBuffer[i + 1];
141 }
142 _pFree = _pBuffer;
143 _pHead = _pTail = &_pBuffer[_queueMax - 1];
144 }
145
146 return ret;
147}
148
149//-----------------------------------------------------------
150// 終了
151//-----------------------------------------------------------
152template<class T, GxAllocatorList::ALLOCATOR_TYPE ALLOCATOR>
154{
155 _pFree = _pHead = _pTail = nullptr;
156 GX_SAFE_FREE_MEMORY(_pBuffer);
157}
158
159//-----------------------------------------------------------
160// エンキュー
163//-----------------------------------------------------------
164template<class T, GxAllocatorList::ALLOCATOR_TYPE ALLOCATOR>
166{
167 // 初期化済みチェック
168 if( !_pHead )
169 {
170 return false;
171 }
172
173 //---- 空きノード取得
174 Node* pNode = nullptr;
175 for(;;)
176 {
177 // Double-Checked Lock パターン
178 auto* pOldFree = (Node*)_pFree;
179 auto* pOldHead = (Node*)_pHead;
180 Node* pOldFreeNext = _pFree->_pNext;
181
182 // 変更チェック → 変更されていたらもう一度取得
183 if( pOldFree != _pFree )
184 {
185 continue;
186 }
187
188 // 満杯チェック
189 if( pOldFree == pOldHead )
190 {
191 GX_TRACE(GX_TRACE_CATEGORY_CORE, "queue is Full!!");
192 return false;
193 }
194
195 // 空き領域取得
196 pNode = pOldFree;
197
198 // キュー先頭を進める
199 if(GxThread::casPointer((volatile void**)(&_pFree), pOldFree, pOldFreeNext))
200 {
201 break;
202 }
203 }
204
205 //---- データ格納
206 pNode->_item = src;
207 pNode->_pNext = nullptr;
208
209 //---- 終端に追加
210 Node* pOldTail = nullptr;
211 Node* pOldTailNext = nullptr;
212 for(;;)
213 {
214 // Double-Checked Lock パターン
215 pOldTail = (Node*)_pTail;
216 pOldTailNext = pOldTail->_pNext;
217
218 // 変更チェック → 変更されていたらもう一度取得
219 if( _pTail != pOldTail )
220 {
221 continue;
222 }
223
224 // 次リストチェック
225 if( !pOldTailNext )
226 {
227 // 末尾のNextポインタ更新
228 if(GxThread::casPointer((volatile void**)(&_pTail->_pNext), nullptr, pNode))
229 {
230 break;
231 }
232 }
233 else
234 {
235 // 他スレッドで更新された → 終端ポインタを更新
236 GxThread::casPointer((volatile void**)(&_pTail), pOldTail, pOldTailNext);
237 }
238 }
239
240 // 終端ポインタを更新 ※次のエンキューで再設定される為、失敗は無視
241 GxThread::casPointer((volatile void**)(&_pTail), pOldTail, pNode);
242
243 return true;
244}
245
246//-----------------------------------------------------------
247// デキュー
250//-----------------------------------------------------------
251template<class T, GxAllocatorList::ALLOCATOR_TYPE ALLOCATOR>
253{
254 // 初期化済みチェック
255 if( !_pHead )
256 {
257 return false;
258 }
259
260 //---- 終端要素取得
261 T temporary;
262 for(;;)
263 {
264 // Double-Checked Lock パターン
265 Node* pOldHead = (Node*)_pHead;
266 Node* pOldTail = (Node*)_pTail;
267 Node* pOldHeadNext = pOldHead->_pNext;
268
269 // 変更チェック → 変更されていたらもう一度取得
270 if( _pHead != pOldHead )
271 {
272 continue;
273 }
274
275 // リスト要素存在チェック
276 if( pOldHead == pOldTail )
277 {
278 // Nextが無ければデータなし
279 if( pOldHeadNext == nullptr )
280 {
281 return false;
282 }
283 // Nextがあれば他スレッドで更新された → 終端ポインタ更新
284 GxThread::casPointer((volatile void**)(&_pTail), pOldTail, pOldHeadNext);
285 }
286 else
287 {
288 // 情報取得
289 temporary = pOldHeadNext->_item;
290
291 // キュー先頭を進める
292 if(GxThread::casPointer((volatile void**)(&_pHead), pOldHead, pOldHeadNext))
293 {
294 break;
295 }
296 }
297 }
298
299 // データ格納
300 dst = temporary;
301
302 return true;
303}
304
305//-----------------------------------------------------------
306// キュー空判定
308//-----------------------------------------------------------
309template<class T, GxAllocatorList::ALLOCATOR_TYPE ALLOCATOR>
311{
313 return (_pHead == _pTail);
314}
315
316//-----------------------------------------------------------
317// データ数を取得
319//-----------------------------------------------------------
320template<class T, GxAllocatorList::ALLOCATOR_TYPE ALLOCATOR>
322{
323 return static_cast<u32>(_pTail - _pHead);
324}
325
326GX_CORE_NAMESPACE_END()
#define GX_ALLOCATE_MEMORY(pAllocatorList, size)
Definition GxAllocator.h:536
#define GX_SAFE_FREE_MEMORY(pAddress)
Definition GxAllocator.h:594
メモリアロケータリスト
Definition GxAllocator.h:347
static GxAllocatorList * getAllocatorList(GxAllocatorList::ALLOCATOR_TYPE number)
アロケータリスト取得 (インデックス指定)
Definition GxAllocator.cpp:284
キュー (ロック不要)
Definition GxLockFreeQueue.h:19
GxLockFreeQueue(void)
コンストラクタ
Definition GxLockFreeQueue.h:42
b32 isEmpty(void) const
キュー空判定
Definition GxLockFreeQueue.h:310
u32 getCount(void) const
データ数を取得
Definition GxLockFreeQueue.h:321
b32 enqueue(const T &src)
エンキュー
Definition GxLockFreeQueue.h:165
~GxLockFreeQueue(void)
デストラクタ
Definition GxLockFreeQueue.h:52
b32 initialize(u32 queueMax)
初期化
Definition GxLockFreeQueue.h:115
b32 dequeue(T &dst)
デキュー
Definition GxLockFreeQueue.h:252
void terminate(void)
終了
Definition GxLockFreeQueue.h:153
static b32 casPointer(volatile void **ppTarget, void *pOld, void *pNew)
ポインタCAS(Compare-And-Swap)
Definition GxThread.cpp:46
static void barrierMemory(void)
メモリバリア
Definition GxThread.cpp:64
ノード (単方向リスト)
Definition GxLockFreeQueue.h:30
T _item
実体定義
Definition GxLockFreeQueue.h:32
struct Node * _pNext
次ノード
Definition GxLockFreeQueue.h:31
32bitブーリアン
Definition GxDefine.h:173