reader_writer_queue.h 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. // ©2013-2020 Cameron Desrochers.
  2. // Distributed under the simplified BSD license (see the license file that
  3. // should have come with this header).
  4. #pragma once
  5. #include <cassert>
  6. #include <cstdint>
  7. #include <cstdlib> // For malloc/free/abort & size_t
  8. #include <memory>
  9. #include <new>
  10. #include <stdexcept>
  11. #include <type_traits>
  12. #include <utility>
  13. #include "common/atomic_helpers.h"
  14. #if __cplusplus > 199711L || _MSC_VER >= 1700 // C++11 or VS2012
  15. #include <chrono>
  16. #endif
  17. // A lock-free queue for a single-consumer, single-producer architecture.
  18. // The queue is also wait-free in the common path (except if more memory
  19. // needs to be allocated, in which case malloc is called).
  20. // Allocates memory sparingly, and only once if the original maximum size
  21. // estimate is never exceeded.
  22. // Tested on x86/x64 processors, but semantics should be correct for all
  23. // architectures (given the right implementations in atomicops.h), provided
  24. // that aligned integer and pointer accesses are naturally atomic.
  25. // Note that there should only be one consumer thread and producer thread;
  26. // Switching roles of the threads, or using multiple consecutive threads for
  27. // one role, is not safe unless properly synchronized.
  28. // Using the queue exclusively from one thread is fine, though a bit silly.
  29. #ifndef MOODYCAMEL_CACHE_LINE_SIZE
  30. #define MOODYCAMEL_CACHE_LINE_SIZE 64
  31. #endif
  32. #ifndef MOODYCAMEL_EXCEPTIONS_ENABLED
  33. #if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || \
  34. (!defined(_MSC_VER) && !defined(__GNUC__))
  35. #define MOODYCAMEL_EXCEPTIONS_ENABLED
  36. #endif
  37. #endif
  38. #ifndef MOODYCAMEL_HAS_EMPLACE
  39. #if !defined(_MSC_VER) || \
  40. _MSC_VER >= 1800 // variadic templates: either a non-MS compiler or VS >= 2013
  41. #define MOODYCAMEL_HAS_EMPLACE 1
  42. #endif
  43. #endif
  44. #ifndef MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE
  45. #if defined(__APPLE__) && defined(__MACH__) && __cplusplus >= 201703L
  46. // This is required to find out what deployment target we are using
  47. #include <CoreFoundation/CoreFoundation.h>
  48. #if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || \
  49. MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_14
  50. // C++17 new(size_t, align_val_t) is not backwards-compatible with older versions of macOS, so we
  51. // can't support over-alignment in this case
  52. #define MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE
  53. #endif
  54. #endif
  55. #endif
  56. #ifndef MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE
  57. #define MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE AE_ALIGN(MOODYCAMEL_CACHE_LINE_SIZE)
  58. #endif
  59. #ifdef AE_VCPP
  60. #pragma warning(push)
  61. #pragma warning(disable : 4324) // structure was padded due to __declspec(align())
  62. #pragma warning(disable : 4820) // padding was added
  63. #pragma warning(disable : 4127) // conditional expression is constant
  64. #endif
  65. namespace Common {
  66. template <typename T, size_t MAX_BLOCK_SIZE = 512>
  67. class MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE ReaderWriterQueue {
  68. // Design: Based on a queue-of-queues. The low-level queues are just
  69. // circular buffers with front and tail indices indicating where the
  70. // next element to dequeue is and where the next element can be enqueued,
  71. // respectively. Each low-level queue is called a "block". Each block
  72. // wastes exactly one element's worth of space to keep the design simple
  73. // (if front == tail then the queue is empty, and can't be full).
  74. // The high-level queue is a circular linked list of blocks; again there
  75. // is a front and tail, but this time they are pointers to the blocks.
  76. // The front block is where the next element to be dequeued is, provided
  77. // the block is not empty. The back block is where elements are to be
  78. // enqueued, provided the block is not full.
  79. // The producer thread owns all the tail indices/pointers. The consumer
  80. // thread owns all the front indices/pointers. Both threads read each
  81. // other's variables, but only the owning thread updates them. E.g. After
  82. // the consumer reads the producer's tail, the tail may change before the
  83. // consumer is done dequeuing an object, but the consumer knows the tail
  84. // will never go backwards, only forwards.
  85. // If there is no room to enqueue an object, an additional block (of
  86. // equal size to the last block) is added. Blocks are never removed.
  87. public:
  88. typedef T value_type;
  89. // Constructs a queue that can hold at least `size` elements without further
  90. // allocations. If more than MAX_BLOCK_SIZE elements are requested,
  91. // then several blocks of MAX_BLOCK_SIZE each are reserved (including
  92. // at least one extra buffer block).
  93. AE_NO_TSAN explicit ReaderWriterQueue(size_t size = 15)
  94. #ifndef NDEBUG
  95. : enqueuing(false), dequeuing(false)
  96. #endif
  97. {
  98. assert(MAX_BLOCK_SIZE == ceilToPow2(MAX_BLOCK_SIZE) &&
  99. "MAX_BLOCK_SIZE must be a power of 2");
  100. assert(MAX_BLOCK_SIZE >= 2 && "MAX_BLOCK_SIZE must be at least 2");
  101. Block* firstBlock = nullptr;
  102. largestBlockSize =
  103. ceilToPow2(size + 1); // We need a spare slot to fit size elements in the block
  104. if (largestBlockSize > MAX_BLOCK_SIZE * 2) {
  105. // We need a spare block in case the producer is writing to a different block the
  106. // consumer is reading from, and wants to enqueue the maximum number of elements. We
  107. // also need a spare element in each block to avoid the ambiguity between front == tail
  108. // meaning "empty" and "full". So the effective number of slots that are guaranteed to
  109. // be usable at any time is the block size - 1 times the number of blocks - 1. Solving
  110. // for size and applying a ceiling to the division gives us (after simplifying):
  111. size_t initialBlockCount = (size + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1);
  112. largestBlockSize = MAX_BLOCK_SIZE;
  113. Block* lastBlock = nullptr;
  114. for (size_t i = 0; i != initialBlockCount; ++i) {
  115. auto block = make_block(largestBlockSize);
  116. if (block == nullptr) {
  117. #ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
  118. throw std::bad_alloc();
  119. #else
  120. abort();
  121. #endif
  122. }
  123. if (firstBlock == nullptr) {
  124. firstBlock = block;
  125. } else {
  126. lastBlock->next = block;
  127. }
  128. lastBlock = block;
  129. block->next = firstBlock;
  130. }
  131. } else {
  132. firstBlock = make_block(largestBlockSize);
  133. if (firstBlock == nullptr) {
  134. #ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
  135. throw std::bad_alloc();
  136. #else
  137. abort();
  138. #endif
  139. }
  140. firstBlock->next = firstBlock;
  141. }
  142. frontBlock = firstBlock;
  143. tailBlock = firstBlock;
  144. // Make sure the reader/writer threads will have the initialized memory setup above:
  145. fence(memory_order_sync);
  146. }
  147. // Note: The queue should not be accessed concurrently while it's
  148. // being moved. It's up to the user to synchronize this.
  149. AE_NO_TSAN ReaderWriterQueue(ReaderWriterQueue&& other)
  150. : frontBlock(other.frontBlock.load()), tailBlock(other.tailBlock.load()),
  151. largestBlockSize(other.largestBlockSize)
  152. #ifndef NDEBUG
  153. ,
  154. enqueuing(false), dequeuing(false)
  155. #endif
  156. {
  157. other.largestBlockSize = 32;
  158. Block* b = other.make_block(other.largestBlockSize);
  159. if (b == nullptr) {
  160. #ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
  161. throw std::bad_alloc();
  162. #else
  163. abort();
  164. #endif
  165. }
  166. b->next = b;
  167. other.frontBlock = b;
  168. other.tailBlock = b;
  169. }
  170. // Note: The queue should not be accessed concurrently while it's
  171. // being moved. It's up to the user to synchronize this.
  172. ReaderWriterQueue& operator=(ReaderWriterQueue&& other) AE_NO_TSAN {
  173. Block* b = frontBlock.load();
  174. frontBlock = other.frontBlock.load();
  175. other.frontBlock = b;
  176. b = tailBlock.load();
  177. tailBlock = other.tailBlock.load();
  178. other.tailBlock = b;
  179. std::swap(largestBlockSize, other.largestBlockSize);
  180. return *this;
  181. }
  182. // Note: The queue should not be accessed concurrently while it's
  183. // being deleted. It's up to the user to synchronize this.
  184. AE_NO_TSAN ~ReaderWriterQueue() {
  185. // Make sure we get the latest version of all variables from other CPUs:
  186. fence(memory_order_sync);
  187. // Destroy any remaining objects in queue and free memory
  188. Block* frontBlock_ = frontBlock;
  189. Block* block = frontBlock_;
  190. do {
  191. Block* nextBlock = block->next;
  192. size_t blockFront = block->front;
  193. size_t blockTail = block->tail;
  194. for (size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask) {
  195. auto element = reinterpret_cast<T*>(block->data + i * sizeof(T));
  196. element->~T();
  197. (void)element;
  198. }
  199. auto rawBlock = block->rawThis;
  200. block->~Block();
  201. std::free(rawBlock);
  202. block = nextBlock;
  203. } while (block != frontBlock_);
  204. }
  205. // Enqueues a copy of element if there is room in the queue.
  206. // Returns true if the element was enqueued, false otherwise.
  207. // Does not allocate memory.
  208. AE_FORCEINLINE bool try_enqueue(T const& element) AE_NO_TSAN {
  209. return inner_enqueue<CannotAlloc>(element);
  210. }
  211. // Enqueues a moved copy of element if there is room in the queue.
  212. // Returns true if the element was enqueued, false otherwise.
  213. // Does not allocate memory.
  214. AE_FORCEINLINE bool try_enqueue(T&& element) AE_NO_TSAN {
  215. return inner_enqueue<CannotAlloc>(std::forward<T>(element));
  216. }
  217. #if MOODYCAMEL_HAS_EMPLACE
  218. // Like try_enqueue() but with emplace semantics (i.e. construct-in-place).
  219. template <typename... Args>
  220. AE_FORCEINLINE bool try_emplace(Args&&... args) AE_NO_TSAN {
  221. return inner_enqueue<CannotAlloc>(std::forward<Args>(args)...);
  222. }
  223. #endif
  224. // Enqueues a copy of element on the queue.
  225. // Allocates an additional block of memory if needed.
  226. // Only fails (returns false) if memory allocation fails.
  227. AE_FORCEINLINE bool enqueue(T const& element) AE_NO_TSAN {
  228. return inner_enqueue<CanAlloc>(element);
  229. }
  230. // Enqueues a moved copy of element on the queue.
  231. // Allocates an additional block of memory if needed.
  232. // Only fails (returns false) if memory allocation fails.
  233. AE_FORCEINLINE bool enqueue(T&& element) AE_NO_TSAN {
  234. return inner_enqueue<CanAlloc>(std::forward<T>(element));
  235. }
  236. #if MOODYCAMEL_HAS_EMPLACE
  237. // Like enqueue() but with emplace semantics (i.e. construct-in-place).
  238. template <typename... Args>
  239. AE_FORCEINLINE bool emplace(Args&&... args) AE_NO_TSAN {
  240. return inner_enqueue<CanAlloc>(std::forward<Args>(args)...);
  241. }
  242. #endif
  243. // Attempts to dequeue an element; if the queue is empty,
  244. // returns false instead. If the queue has at least one element,
  245. // moves front to result using operator=, then returns true.
  246. template <typename U>
  247. bool try_dequeue(U& result) AE_NO_TSAN {
  248. #ifndef NDEBUG
  249. ReentrantGuard guard(this->dequeuing);
  250. #endif
  251. // High-level pseudocode:
  252. // Remember where the tail block is
  253. // If the front block has an element in it, dequeue it
  254. // Else
  255. // If front block was the tail block when we entered the function, return false
  256. // Else advance to next block and dequeue the item there
  257. // Note that we have to use the value of the tail block from before we check if the front
  258. // block is full or not, in case the front block is empty and then, before we check if the
  259. // tail block is at the front block or not, the producer fills up the front block *and
  260. // moves on*, which would make us skip a filled block. Seems unlikely, but was consistently
  261. // reproducible in practice.
  262. // In order to avoid overhead in the common case, though, we do a double-checked pattern
  263. // where we have the fast path if the front block is not empty, then read the tail block,
  264. // then re-read the front block and check if it's not empty again, then check if the tail
  265. // block has advanced.
  266. Block* frontBlock_ = frontBlock.load();
  267. size_t blockTail = frontBlock_->localTail;
  268. size_t blockFront = frontBlock_->front.load();
  269. if (blockFront != blockTail ||
  270. blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
  271. fence(memory_order_acquire);
  272. non_empty_front_block:
  273. // Front block not empty, dequeue from here
  274. auto element = reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
  275. result = std::move(*element);
  276. element->~T();
  277. blockFront = (blockFront + 1) & frontBlock_->sizeMask;
  278. fence(memory_order_release);
  279. frontBlock_->front = blockFront;
  280. } else if (frontBlock_ != tailBlock.load()) {
  281. fence(memory_order_acquire);
  282. frontBlock_ = frontBlock.load();
  283. blockTail = frontBlock_->localTail = frontBlock_->tail.load();
  284. blockFront = frontBlock_->front.load();
  285. fence(memory_order_acquire);
  286. if (blockFront != blockTail) {
  287. // Oh look, the front block isn't empty after all
  288. goto non_empty_front_block;
  289. }
  290. // Front block is empty but there's another block ahead, advance to it
  291. Block* nextBlock = frontBlock_->next;
  292. // Don't need an acquire fence here since next can only ever be set on the tailBlock,
  293. // and we're not the tailBlock, and we did an acquire earlier after reading tailBlock
  294. // which ensures next is up-to-date on this CPU in case we recently were at tailBlock.
  295. size_t nextBlockFront = nextBlock->front.load();
  296. size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
  297. fence(memory_order_acquire);
  298. // Since the tailBlock is only ever advanced after being written to,
  299. // we know there's for sure an element to dequeue on it
  300. assert(nextBlockFront != nextBlockTail);
  301. AE_UNUSED(nextBlockTail);
  302. // We're done with this block, let the producer use it if it needs
  303. fence(memory_order_release); // Expose possibly pending changes to frontBlock->front
  304. // from last dequeue
  305. frontBlock = frontBlock_ = nextBlock;
  306. compiler_fence(memory_order_release); // Not strictly needed
  307. auto element = reinterpret_cast<T*>(frontBlock_->data + nextBlockFront * sizeof(T));
  308. result = std::move(*element);
  309. element->~T();
  310. nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
  311. fence(memory_order_release);
  312. frontBlock_->front = nextBlockFront;
  313. } else {
  314. // No elements in current block and no other block to advance to
  315. return false;
  316. }
  317. return true;
  318. }
  319. // Returns a pointer to the front element in the queue (the one that
  320. // would be removed next by a call to `try_dequeue` or `pop`). If the
  321. // queue appears empty at the time the method is called, nullptr is
  322. // returned instead.
  323. // Must be called only from the consumer thread.
  324. T* peek() const AE_NO_TSAN {
  325. #ifndef NDEBUG
  326. ReentrantGuard guard(this->dequeuing);
  327. #endif
  328. // See try_dequeue() for reasoning
  329. Block* frontBlock_ = frontBlock.load();
  330. size_t blockTail = frontBlock_->localTail;
  331. size_t blockFront = frontBlock_->front.load();
  332. if (blockFront != blockTail ||
  333. blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
  334. fence(memory_order_acquire);
  335. non_empty_front_block:
  336. return reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
  337. } else if (frontBlock_ != tailBlock.load()) {
  338. fence(memory_order_acquire);
  339. frontBlock_ = frontBlock.load();
  340. blockTail = frontBlock_->localTail = frontBlock_->tail.load();
  341. blockFront = frontBlock_->front.load();
  342. fence(memory_order_acquire);
  343. if (blockFront != blockTail) {
  344. goto non_empty_front_block;
  345. }
  346. Block* nextBlock = frontBlock_->next;
  347. size_t nextBlockFront = nextBlock->front.load();
  348. fence(memory_order_acquire);
  349. assert(nextBlockFront != nextBlock->tail.load());
  350. return reinterpret_cast<T*>(nextBlock->data + nextBlockFront * sizeof(T));
  351. }
  352. return nullptr;
  353. }
  354. // Removes the front element from the queue, if any, without returning it.
  355. // Returns true on success, or false if the queue appeared empty at the time
  356. // `pop` was called.
  357. bool pop() AE_NO_TSAN {
  358. #ifndef NDEBUG
  359. ReentrantGuard guard(this->dequeuing);
  360. #endif
  361. // See try_dequeue() for reasoning
  362. Block* frontBlock_ = frontBlock.load();
  363. size_t blockTail = frontBlock_->localTail;
  364. size_t blockFront = frontBlock_->front.load();
  365. if (blockFront != blockTail ||
  366. blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
  367. fence(memory_order_acquire);
  368. non_empty_front_block:
  369. auto element = reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
  370. element->~T();
  371. blockFront = (blockFront + 1) & frontBlock_->sizeMask;
  372. fence(memory_order_release);
  373. frontBlock_->front = blockFront;
  374. } else if (frontBlock_ != tailBlock.load()) {
  375. fence(memory_order_acquire);
  376. frontBlock_ = frontBlock.load();
  377. blockTail = frontBlock_->localTail = frontBlock_->tail.load();
  378. blockFront = frontBlock_->front.load();
  379. fence(memory_order_acquire);
  380. if (blockFront != blockTail) {
  381. goto non_empty_front_block;
  382. }
  383. // Front block is empty but there's another block ahead, advance to it
  384. Block* nextBlock = frontBlock_->next;
  385. size_t nextBlockFront = nextBlock->front.load();
  386. size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
  387. fence(memory_order_acquire);
  388. assert(nextBlockFront != nextBlockTail);
  389. AE_UNUSED(nextBlockTail);
  390. fence(memory_order_release);
  391. frontBlock = frontBlock_ = nextBlock;
  392. compiler_fence(memory_order_release);
  393. auto element = reinterpret_cast<T*>(frontBlock_->data + nextBlockFront * sizeof(T));
  394. element->~T();
  395. nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
  396. fence(memory_order_release);
  397. frontBlock_->front = nextBlockFront;
  398. } else {
  399. // No elements in current block and no other block to advance to
  400. return false;
  401. }
  402. return true;
  403. }
  404. // Returns the approximate number of items currently in the queue.
  405. // Safe to call from both the producer and consumer threads.
  406. inline size_t size_approx() const AE_NO_TSAN {
  407. size_t result = 0;
  408. Block* frontBlock_ = frontBlock.load();
  409. Block* block = frontBlock_;
  410. do {
  411. fence(memory_order_acquire);
  412. size_t blockFront = block->front.load();
  413. size_t blockTail = block->tail.load();
  414. result += (blockTail - blockFront) & block->sizeMask;
  415. block = block->next.load();
  416. } while (block != frontBlock_);
  417. return result;
  418. }
  419. // Returns the total number of items that could be enqueued without incurring
  420. // an allocation when this queue is empty.
  421. // Safe to call from both the producer and consumer threads.
  422. //
  423. // NOTE: The actual capacity during usage may be different depending on the consumer.
  424. // If the consumer is removing elements concurrently, the producer cannot add to
  425. // the block the consumer is removing from until it's completely empty, except in
  426. // the case where the producer was writing to the same block the consumer was
  427. // reading from the whole time.
  428. inline size_t max_capacity() const {
  429. size_t result = 0;
  430. Block* frontBlock_ = frontBlock.load();
  431. Block* block = frontBlock_;
  432. do {
  433. fence(memory_order_acquire);
  434. result += block->sizeMask;
  435. block = block->next.load();
  436. } while (block != frontBlock_);
  437. return result;
  438. }
  439. private:
  440. enum AllocationMode { CanAlloc, CannotAlloc };
  441. #if MOODYCAMEL_HAS_EMPLACE
  442. template <AllocationMode canAlloc, typename... Args>
  443. bool inner_enqueue(Args&&... args) AE_NO_TSAN
  444. #else
  445. template <AllocationMode canAlloc, typename U>
  446. bool inner_enqueue(U&& element) AE_NO_TSAN
  447. #endif
  448. {
  449. #ifndef NDEBUG
  450. ReentrantGuard guard(this->enqueuing);
  451. #endif
  452. // High-level pseudocode (assuming we're allowed to alloc a new block):
  453. // If room in tail block, add to tail
  454. // Else check next block
  455. // If next block is not the head block, enqueue on next block
  456. // Else create a new block and enqueue there
  457. // Advance tail to the block we just enqueued to
  458. Block* tailBlock_ = tailBlock.load();
  459. size_t blockFront = tailBlock_->localFront;
  460. size_t blockTail = tailBlock_->tail.load();
  461. size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
  462. if (nextBlockTail != blockFront ||
  463. nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load())) {
  464. fence(memory_order_acquire);
  465. // This block has room for at least one more element
  466. char* location = tailBlock_->data + blockTail * sizeof(T);
  467. #if MOODYCAMEL_HAS_EMPLACE
  468. new (location) T(std::forward<Args>(args)...);
  469. #else
  470. new (location) T(std::forward<U>(element));
  471. #endif
  472. fence(memory_order_release);
  473. tailBlock_->tail = nextBlockTail;
  474. } else {
  475. fence(memory_order_acquire);
  476. if (tailBlock_->next.load() != frontBlock) {
  477. // Note that the reason we can't advance to the frontBlock and start adding new
  478. // entries there is because if we did, then dequeue would stay in that block,
  479. // eventually reading the new values, instead of advancing to the next full block
  480. // (whose values were enqueued first and so should be consumed first).
  481. fence(memory_order_acquire); // Ensure we get latest writes if we got the latest
  482. // frontBlock
  483. // tailBlock is full, but there's a free block ahead, use it
  484. Block* tailBlockNext = tailBlock_->next.load();
  485. size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front.load();
  486. nextBlockTail = tailBlockNext->tail.load();
  487. fence(memory_order_acquire);
  488. // This block must be empty since it's not the head block and we
  489. // go through the blocks in a circle
  490. assert(nextBlockFront == nextBlockTail);
  491. tailBlockNext->localFront = nextBlockFront;
  492. char* location = tailBlockNext->data + nextBlockTail * sizeof(T);
  493. #if MOODYCAMEL_HAS_EMPLACE
  494. new (location) T(std::forward<Args>(args)...);
  495. #else
  496. new (location) T(std::forward<U>(element));
  497. #endif
  498. tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask;
  499. fence(memory_order_release);
  500. tailBlock = tailBlockNext;
  501. } else if (canAlloc == CanAlloc) {
  502. // tailBlock is full and there's no free block ahead; create a new block
  503. auto newBlockSize =
  504. largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2;
  505. auto newBlock = make_block(newBlockSize);
  506. if (newBlock == nullptr) {
  507. // Could not allocate a block!
  508. return false;
  509. }
  510. largestBlockSize = newBlockSize;
  511. #if MOODYCAMEL_HAS_EMPLACE
  512. new (newBlock->data) T(std::forward<Args>(args)...);
  513. #else
  514. new (newBlock->data) T(std::forward<U>(element));
  515. #endif
  516. assert(newBlock->front == 0);
  517. newBlock->tail = newBlock->localTail = 1;
  518. newBlock->next = tailBlock_->next.load();
  519. tailBlock_->next = newBlock;
  520. // Might be possible for the dequeue thread to see the new tailBlock->next
  521. // *without* seeing the new tailBlock value, but this is OK since it can't
  522. // advance to the next block until tailBlock is set anyway (because the only
  523. // case where it could try to read the next is if it's already at the tailBlock,
  524. // and it won't advance past tailBlock in any circumstance).
  525. fence(memory_order_release);
  526. tailBlock = newBlock;
  527. } else if (canAlloc == CannotAlloc) {
  528. // Would have had to allocate a new block to enqueue, but not allowed
  529. return false;
  530. } else {
  531. assert(false && "Should be unreachable code");
  532. return false;
  533. }
  534. }
  535. return true;
  536. }
  537. // Disable copying
  538. ReaderWriterQueue(ReaderWriterQueue const&) {}
  539. // Disable assignment
  540. ReaderWriterQueue& operator=(ReaderWriterQueue const&) {}
  541. AE_FORCEINLINE static size_t ceilToPow2(size_t x) {
  542. // From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  543. --x;
  544. x |= x >> 1;
  545. x |= x >> 2;
  546. x |= x >> 4;
  547. for (size_t i = 1; i < sizeof(size_t); i <<= 1) {
  548. x |= x >> (i << 3);
  549. }
  550. ++x;
  551. return x;
  552. }
  553. template <typename U>
  554. static AE_FORCEINLINE char* align_for(char* ptr) AE_NO_TSAN {
  555. const std::size_t alignment = std::alignment_of<U>::value;
  556. return ptr + (alignment - (reinterpret_cast<std::uintptr_t>(ptr) % alignment)) % alignment;
  557. }
  558. private:
  559. #ifndef NDEBUG
  560. struct ReentrantGuard {
  561. AE_NO_TSAN ReentrantGuard(weak_atomic<bool>& _inSection) : inSection(_inSection) {
  562. assert(!inSection &&
  563. "Concurrent (or re-entrant) enqueue or dequeue operation detected (only one "
  564. "thread at a time may hold the producer or consumer role)");
  565. inSection = true;
  566. }
  567. AE_NO_TSAN ~ReentrantGuard() {
  568. inSection = false;
  569. }
  570. private:
  571. ReentrantGuard& operator=(ReentrantGuard const&);
  572. private:
  573. weak_atomic<bool>& inSection;
  574. };
  575. #endif
  576. struct Block {
  577. // Avoid false-sharing by putting highly contended variables on their own cache lines
  578. weak_atomic<size_t> front; // (Atomic) Elements are read from here
  579. size_t localTail; // An uncontended shadow copy of tail, owned by the consumer
  580. char cachelineFiller0[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic<size_t>) -
  581. sizeof(size_t)];
  582. weak_atomic<size_t> tail; // (Atomic) Elements are enqueued here
  583. size_t localFront;
  584. char cachelineFiller1[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic<size_t>) -
  585. sizeof(size_t)]; // next isn't very contended, but we don't want it on
  586. // the same cache line as tail (which is)
  587. weak_atomic<Block*> next; // (Atomic)
  588. char* data; // Contents (on heap) are aligned to T's alignment
  589. const size_t sizeMask;
  590. // size must be a power of two (and greater than 0)
  591. AE_NO_TSAN Block(size_t const& _size, char* _rawThis, char* _data)
  592. : front(0UL), localTail(0), tail(0UL), localFront(0), next(nullptr), data(_data),
  593. sizeMask(_size - 1), rawThis(_rawThis) {}
  594. private:
  595. // C4512 - Assignment operator could not be generated
  596. Block& operator=(Block const&);
  597. public:
  598. char* rawThis;
  599. };
  600. static Block* make_block(size_t capacity) AE_NO_TSAN {
  601. // Allocate enough memory for the block itself, as well as all the elements it will contain
  602. auto size = sizeof(Block) + std::alignment_of<Block>::value - 1;
  603. size += sizeof(T) * capacity + std::alignment_of<T>::value - 1;
  604. auto newBlockRaw = static_cast<char*>(std::malloc(size));
  605. if (newBlockRaw == nullptr) {
  606. return nullptr;
  607. }
  608. auto newBlockAligned = align_for<Block>(newBlockRaw);
  609. auto newBlockData = align_for<T>(newBlockAligned + sizeof(Block));
  610. return new (newBlockAligned) Block(capacity, newBlockRaw, newBlockData);
  611. }
  612. private:
  613. weak_atomic<Block*> frontBlock; // (Atomic) Elements are dequeued from this block
  614. char cachelineFiller[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic<Block*>)];
  615. weak_atomic<Block*> tailBlock; // (Atomic) Elements are enqueued to this block
  616. size_t largestBlockSize;
  617. #ifndef NDEBUG
  618. weak_atomic<bool> enqueuing;
  619. mutable weak_atomic<bool> dequeuing;
  620. #endif
  621. };
  622. // Like ReaderWriterQueue, but also providees blocking operations
  623. template <typename T, size_t MAX_BLOCK_SIZE = 512>
  624. class BlockingReaderWriterQueue {
  625. private:
  626. typedef ::Common::ReaderWriterQueue<T, MAX_BLOCK_SIZE> ReaderWriterQueue;
  627. public:
  628. explicit BlockingReaderWriterQueue(size_t size = 15) AE_NO_TSAN
  629. : inner(size),
  630. sema(new spsc_sema::LightweightSemaphore()) {}
  631. BlockingReaderWriterQueue(BlockingReaderWriterQueue&& other) AE_NO_TSAN
  632. : inner(std::move(other.inner)),
  633. sema(std::move(other.sema)) {}
  634. BlockingReaderWriterQueue& operator=(BlockingReaderWriterQueue&& other) AE_NO_TSAN {
  635. std::swap(sema, other.sema);
  636. std::swap(inner, other.inner);
  637. return *this;
  638. }
  639. // Enqueues a copy of element if there is room in the queue.
  640. // Returns true if the element was enqueued, false otherwise.
  641. // Does not allocate memory.
  642. AE_FORCEINLINE bool try_enqueue(T const& element) AE_NO_TSAN {
  643. if (inner.try_enqueue(element)) {
  644. sema->signal();
  645. return true;
  646. }
  647. return false;
  648. }
  649. // Enqueues a moved copy of element if there is room in the queue.
  650. // Returns true if the element was enqueued, false otherwise.
  651. // Does not allocate memory.
  652. AE_FORCEINLINE bool try_enqueue(T&& element) AE_NO_TSAN {
  653. if (inner.try_enqueue(std::forward<T>(element))) {
  654. sema->signal();
  655. return true;
  656. }
  657. return false;
  658. }
  659. #if MOODYCAMEL_HAS_EMPLACE
  660. // Like try_enqueue() but with emplace semantics (i.e. construct-in-place).
  661. template <typename... Args>
  662. AE_FORCEINLINE bool try_emplace(Args&&... args) AE_NO_TSAN {
  663. if (inner.try_emplace(std::forward<Args>(args)...)) {
  664. sema->signal();
  665. return true;
  666. }
  667. return false;
  668. }
  669. #endif
  670. // Enqueues a copy of element on the queue.
  671. // Allocates an additional block of memory if needed.
  672. // Only fails (returns false) if memory allocation fails.
  673. AE_FORCEINLINE bool enqueue(T const& element) AE_NO_TSAN {
  674. if (inner.enqueue(element)) {
  675. sema->signal();
  676. return true;
  677. }
  678. return false;
  679. }
  680. // Enqueues a moved copy of element on the queue.
  681. // Allocates an additional block of memory if needed.
  682. // Only fails (returns false) if memory allocation fails.
  683. AE_FORCEINLINE bool enqueue(T&& element) AE_NO_TSAN {
  684. if (inner.enqueue(std::forward<T>(element))) {
  685. sema->signal();
  686. return true;
  687. }
  688. return false;
  689. }
  690. #if MOODYCAMEL_HAS_EMPLACE
  691. // Like enqueue() but with emplace semantics (i.e. construct-in-place).
  692. template <typename... Args>
  693. AE_FORCEINLINE bool emplace(Args&&... args) AE_NO_TSAN {
  694. if (inner.emplace(std::forward<Args>(args)...)) {
  695. sema->signal();
  696. return true;
  697. }
  698. return false;
  699. }
  700. #endif
  701. // Attempts to dequeue an element; if the queue is empty,
  702. // returns false instead. If the queue has at least one element,
  703. // moves front to result using operator=, then returns true.
  704. template <typename U>
  705. bool try_dequeue(U& result) AE_NO_TSAN {
  706. if (sema->tryWait()) {
  707. bool success = inner.try_dequeue(result);
  708. assert(success);
  709. AE_UNUSED(success);
  710. return true;
  711. }
  712. return false;
  713. }
  714. // Attempts to dequeue an element; if the queue is empty,
  715. // waits until an element is available, then dequeues it.
  716. template <typename U>
  717. void wait_dequeue(U& result) AE_NO_TSAN {
  718. while (!sema->wait())
  719. ;
  720. bool success = inner.try_dequeue(result);
  721. AE_UNUSED(result);
  722. assert(success);
  723. AE_UNUSED(success);
  724. }
  725. // Attempts to dequeue an element; if the queue is empty,
  726. // waits until an element is available up to the specified timeout,
  727. // then dequeues it and returns true, or returns false if the timeout
  728. // expires before an element can be dequeued.
  729. // Using a negative timeout indicates an indefinite timeout,
  730. // and is thus functionally equivalent to calling wait_dequeue.
  731. template <typename U>
  732. bool wait_dequeue_timed(U& result, std::int64_t timeout_usecs) AE_NO_TSAN {
  733. if (!sema->wait(timeout_usecs)) {
  734. return false;
  735. }
  736. bool success = inner.try_dequeue(result);
  737. AE_UNUSED(result);
  738. assert(success);
  739. AE_UNUSED(success);
  740. return true;
  741. }
  742. #if __cplusplus > 199711L || _MSC_VER >= 1700
  743. // Attempts to dequeue an element; if the queue is empty,
  744. // waits until an element is available up to the specified timeout,
  745. // then dequeues it and returns true, or returns false if the timeout
  746. // expires before an element can be dequeued.
  747. // Using a negative timeout indicates an indefinite timeout,
  748. // and is thus functionally equivalent to calling wait_dequeue.
  749. template <typename U, typename Rep, typename Period>
  750. inline bool wait_dequeue_timed(U& result,
  751. std::chrono::duration<Rep, Period> const& timeout) AE_NO_TSAN {
  752. return wait_dequeue_timed(
  753. result, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
  754. }
  755. #endif
  756. // Returns a pointer to the front element in the queue (the one that
  757. // would be removed next by a call to `try_dequeue` or `pop`). If the
  758. // queue appears empty at the time the method is called, nullptr is
  759. // returned instead.
  760. // Must be called only from the consumer thread.
  761. AE_FORCEINLINE T* peek() const AE_NO_TSAN {
  762. return inner.peek();
  763. }
  764. // Removes the front element from the queue, if any, without returning it.
  765. // Returns true on success, or false if the queue appeared empty at the time
  766. // `pop` was called.
  767. AE_FORCEINLINE bool pop() AE_NO_TSAN {
  768. if (sema->tryWait()) {
  769. bool result = inner.pop();
  770. assert(result);
  771. AE_UNUSED(result);
  772. return true;
  773. }
  774. return false;
  775. }
  776. // Returns the approximate number of items currently in the queue.
  777. // Safe to call from both the producer and consumer threads.
  778. AE_FORCEINLINE size_t size_approx() const AE_NO_TSAN {
  779. return sema->availableApprox();
  780. }
  781. // Returns the total number of items that could be enqueued without incurring
  782. // an allocation when this queue is empty.
  783. // Safe to call from both the producer and consumer threads.
  784. //
  785. // NOTE: The actual capacity during usage may be different depending on the consumer.
  786. // If the consumer is removing elements concurrently, the producer cannot add to
  787. // the block the consumer is removing from until it's completely empty, except in
  788. // the case where the producer was writing to the same block the consumer was
  789. // reading from the whole time.
  790. AE_FORCEINLINE size_t max_capacity() const {
  791. return inner.max_capacity();
  792. }
  793. private:
  794. // Disable copying & assignment
  795. BlockingReaderWriterQueue(BlockingReaderWriterQueue const&) {}
  796. BlockingReaderWriterQueue& operator=(BlockingReaderWriterQueue const&) {}
  797. private:
  798. ReaderWriterQueue inner;
  799. std::unique_ptr<spsc_sema::LightweightSemaphore> sema;
  800. };
  801. } // namespace Common
  802. #ifdef AE_VCPP
  803. #pragma warning(pop)
  804. #endif