1
- // ©2013 Cameron Desrochers.
1
+ // ©2013-2015 Cameron Desrochers.
2
2
// Distributed under the simplified BSD license (see the license file that
3
3
// should have come with this header).
4
4
@@ -75,6 +75,8 @@ class ReaderWriterQueue
75
75
assert (MAX_BLOCK_SIZE == ceilToPow2 (MAX_BLOCK_SIZE) && " MAX_BLOCK_SIZE must be a power of 2" );
76
76
assert (MAX_BLOCK_SIZE >= 2 && " MAX_BLOCK_SIZE must be at least 2" );
77
77
78
+ Block* firstBlock = nullptr ;
79
+
78
80
largestBlockSize = ceilToPow2 (maxSize + 1 ); // We need a spare slot to fit maxSize elements in the block
79
81
if (largestBlockSize > MAX_BLOCK_SIZE * 2 ) {
80
82
// We need a spare block in case the producer is writing to a different block the consumer is reading from, and
@@ -84,7 +86,6 @@ class ReaderWriterQueue
84
86
// number of blocks - 1. Solving for maxSize and applying a ceiling to the division gives us (after simplifying):
85
87
size_t initialBlockCount = (maxSize + MAX_BLOCK_SIZE * 2 - 3 ) / (MAX_BLOCK_SIZE - 1 );
86
88
largestBlockSize = MAX_BLOCK_SIZE;
87
- Block* firstBlock = nullptr ;
88
89
Block* lastBlock = nullptr ;
89
90
for (size_t i = 0 ; i != initialBlockCount; ++i) {
90
91
auto block = make_block (largestBlockSize);
@@ -100,18 +101,16 @@ class ReaderWriterQueue
100
101
lastBlock = block;
101
102
block->next = firstBlock;
102
103
}
103
- frontBlock = firstBlock;
104
- tailBlock = lastBlock;
105
104
}
106
105
else {
107
- auto firstBlock = make_block (largestBlockSize);
106
+ firstBlock = make_block (largestBlockSize);
108
107
if (firstBlock == nullptr ) {
109
108
throw std::bad_alloc ();
110
109
}
111
110
firstBlock->next = firstBlock;
112
- frontBlock = firstBlock;
113
- tailBlock = firstBlock;
114
111
}
112
+ frontBlock = firstBlock;
113
+ tailBlock = firstBlock;
115
114
116
115
// Make sure the reader/writer threads will have the initialized memory setup above:
117
116
fence (memory_order_sync);
@@ -132,7 +131,7 @@ class ReaderWriterQueue
132
131
size_t blockFront = block->front ;
133
132
size_t blockTail = block->tail ;
134
133
135
- for (size_t i = blockFront; i != blockTail; i = (i + 1 ) & block->sizeMask () ) {
134
+ for (size_t i = blockFront; i != blockTail; i = (i + 1 ) & block->sizeMask ) {
136
135
auto element = reinterpret_cast <T*>(block->data + i * sizeof (T));
137
136
element->~T ();
138
137
(void )element;
@@ -208,11 +207,10 @@ class ReaderWriterQueue
208
207
// block has advanced.
209
208
210
209
Block* frontBlock_ = frontBlock.load ();
211
- Block* tailBlock_;
212
210
size_t blockTail = frontBlock_->localTail ;
213
211
size_t blockFront = frontBlock_->front .load ();
214
212
215
- if (blockFront != blockTail || blockFront != (blockTail = frontBlock_->localTail = frontBlock_->tail .load ())) {
213
+ if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail .load ())) {
216
214
fence (memory_order_acquire);
217
215
218
216
non_empty_front_block:
@@ -221,12 +219,12 @@ class ReaderWriterQueue
221
219
result = std::move (*element);
222
220
element->~T ();
223
221
224
- blockFront = (blockFront + 1 ) & frontBlock_->sizeMask () ;
222
+ blockFront = (blockFront + 1 ) & frontBlock_->sizeMask ;
225
223
226
224
fence (memory_order_release);
227
225
frontBlock_->front = blockFront;
228
226
}
229
- else if (frontBlock_ != (tailBlock_ = tailBlock.load () )) {
227
+ else if (frontBlock_ != tailBlock.load ()) {
230
228
fence (memory_order_acquire);
231
229
232
230
frontBlock_ = frontBlock.load ();
@@ -265,7 +263,7 @@ class ReaderWriterQueue
265
263
result = std::move (*element);
266
264
element->~T ();
267
265
268
- nextBlockFront = (nextBlockFront + 1 ) & frontBlock_->sizeMask () ;
266
+ nextBlockFront = (nextBlockFront + 1 ) & frontBlock_->sizeMask ;
269
267
270
268
fence (memory_order_release);
271
269
frontBlock_->front = nextBlockFront;
@@ -292,16 +290,15 @@ class ReaderWriterQueue
292
290
// See try_dequeue() for reasoning
293
291
294
292
Block* frontBlock_ = frontBlock.load ();
295
- Block* tailBlock_;
296
293
size_t blockTail = frontBlock_->localTail ;
297
294
size_t blockFront = frontBlock_->front .load ();
298
295
299
- if (blockFront != blockTail || blockFront != (blockTail = frontBlock_->localTail = frontBlock_->tail .load ())) {
296
+ if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail .load ())) {
300
297
fence (memory_order_acquire);
301
298
non_empty_front_block:
302
299
return reinterpret_cast <T*>(frontBlock_->data + blockFront * sizeof (T));
303
300
}
304
- else if (frontBlock_ != (tailBlock_ = tailBlock.load () )) {
301
+ else if (frontBlock_ != tailBlock.load ()) {
305
302
fence (memory_order_acquire);
306
303
frontBlock_ = frontBlock.load ();
307
304
blockTail = frontBlock_->localTail = frontBlock_->tail .load ();
@@ -335,23 +332,22 @@ class ReaderWriterQueue
335
332
// See try_dequeue() for reasoning
336
333
337
334
Block* frontBlock_ = frontBlock.load ();
338
- Block* tailBlock_;
339
335
size_t blockTail = frontBlock_->localTail ;
340
336
size_t blockFront = frontBlock_->front .load ();
341
337
342
- if (blockFront != blockTail || blockFront != (blockTail = frontBlock_->localTail = frontBlock_->tail .load ())) {
338
+ if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail .load ())) {
343
339
fence (memory_order_acquire);
344
340
345
341
non_empty_front_block:
346
342
auto element = reinterpret_cast <T*>(frontBlock_->data + blockFront * sizeof (T));
347
343
element->~T ();
348
344
349
- blockFront = (blockFront + 1 ) & frontBlock_->sizeMask () ;
345
+ blockFront = (blockFront + 1 ) & frontBlock_->sizeMask ;
350
346
351
347
fence (memory_order_release);
352
348
frontBlock_->front = blockFront;
353
349
}
354
- else if (frontBlock_ != (tailBlock_ = tailBlock.load () )) {
350
+ else if (frontBlock_ != tailBlock.load ()) {
355
351
fence (memory_order_acquire);
356
352
frontBlock_ = frontBlock.load ();
357
353
blockTail = frontBlock_->localTail = frontBlock_->tail .load ();
@@ -380,7 +376,7 @@ class ReaderWriterQueue
380
376
auto element = reinterpret_cast <T*>(frontBlock_->data + nextBlockFront * sizeof (T));
381
377
element->~T ();
382
378
383
- nextBlockFront = (nextBlockFront + 1 ) & frontBlock_->sizeMask () ;
379
+ nextBlockFront = (nextBlockFront + 1 ) & frontBlock_->sizeMask ;
384
380
385
381
fence (memory_order_release);
386
382
frontBlock_->front = nextBlockFront;
@@ -404,7 +400,7 @@ class ReaderWriterQueue
404
400
fence (memory_order_acquire);
405
401
size_t blockFront = block->front .load ();
406
402
size_t blockTail = block->tail .load ();
407
- result += (blockTail - blockFront) & block->sizeMask () ;
403
+ result += (blockTail - blockFront) & block->sizeMask ;
408
404
block = block->next .load ();
409
405
} while (block != frontBlock_);
410
406
return result;
@@ -432,8 +428,8 @@ class ReaderWriterQueue
432
428
size_t blockFront = tailBlock_->localFront ;
433
429
size_t blockTail = tailBlock_->tail .load ();
434
430
435
- size_t nextBlockTail = (blockTail + 1 ) & tailBlock_->sizeMask () ;
436
- if (nextBlockTail != blockFront || nextBlockTail != (blockFront = tailBlock_->localFront = tailBlock_->front .load ())) {
431
+ size_t nextBlockTail = (blockTail + 1 ) & tailBlock_->sizeMask ;
432
+ if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front .load ())) {
437
433
fence (memory_order_acquire);
438
434
// This block has room for at least one more element
439
435
char * location = tailBlock_->data + blockTail * sizeof (T);
@@ -466,7 +462,7 @@ class ReaderWriterQueue
466
462
char * location = tailBlockNext->data + nextBlockTail * sizeof (T);
467
463
new (location) T (std::forward<U>(element));
468
464
469
- tailBlockNext->tail = (nextBlockTail + 1 ) & tailBlockNext->sizeMask () ;
465
+ tailBlockNext->tail = (nextBlockTail + 1 ) & tailBlockNext->sizeMask ;
470
466
471
467
fence (memory_order_release);
472
468
tailBlock = tailBlockNext;
@@ -580,14 +576,12 @@ class ReaderWriterQueue
580
576
581
577
char * data; // Contents (on heap) are aligned to T's alignment
582
578
583
- const size_t size;
584
-
585
- AE_FORCEINLINE size_t sizeMask () const { return size - 1 ; }
579
+ const size_t sizeMask;
586
580
587
581
588
582
// size must be a power of two (and greater than 0)
589
583
Block (size_t const & _size, char * rawThis, char * _data)
590
- : front(0 ), localTail(0 ), tail(0 ), localFront(0 ), next(nullptr ), data(_data), size (_size), rawThis(rawThis)
584
+ : front(0 ), localTail(0 ), tail(0 ), localFront(0 ), next(nullptr ), data(_data), sizeMask (_size - 1 ), rawThis(rawThis)
591
585
{
592
586
}
593
587
0 commit comments