| 23 | // and the removal of producer-specific dequeue methods. |
| 24 | template<typename T, typename Traits = ConcurrentQueueDefaultTraits> |
| 25 | class BlockingConcurrentQueue |
| 26 | { |
| 27 | private: |
| 28 | typedef ::moodycamel::ConcurrentQueue<T, Traits> ConcurrentQueue; |
| 29 | typedef ::moodycamel::LightweightSemaphore LightweightSemaphore; |
| 30 | |
| 31 | public: |
| 32 | typedef typename ConcurrentQueue::producer_token_t producer_token_t; |
| 33 | typedef typename ConcurrentQueue::consumer_token_t consumer_token_t; |
| 34 | |
| 35 | typedef typename ConcurrentQueue::index_t index_t; |
| 36 | typedef typename ConcurrentQueue::size_t size_t; |
| 37 | typedef typename std::make_signed<size_t>::type ssize_t; |
| 38 | |
| 39 | static const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE; |
| 40 | static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD; |
| 41 | static const size_t EXPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE; |
| 42 | static const size_t IMPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE; |
| 43 | static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; |
| 44 | static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE; |
| 45 | static const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE; |
| 46 | |
| 47 | public: |
| 48 | // Creates a queue with at least `capacity` element slots; note that the |
| 49 | // actual number of elements that can be inserted without additional memory |
| 50 | // allocation depends on the number of producers and the block size (e.g. if |
| 51 | // the block size is equal to `capacity`, only a single block will be allocated |
| 52 | // up-front, which means only a single producer will be able to enqueue elements |
| 53 | // without an extra allocation -- blocks aren't shared between producers). |
| 54 | // This method is not thread safe -- it is up to the user to ensure that the |
| 55 | // queue is fully constructed before it starts being used by other threads (this |
| 56 | // includes making the memory effects of construction visible, possibly with a |
| 57 | // memory barrier). |
| 58 | explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) |
| 59 | : inner(capacity), sema(create<LightweightSemaphore, ssize_t, int>(0, static_cast<int>(Traits::MAX_SEMA_SPINS)), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>) |
| 60 | { |
| 61 | assert(reinterpret_cast<ConcurrentQueue*>(reinterpret_cast<BlockingConcurrentQueue*>(1)) == &(reinterpret_cast<BlockingConcurrentQueue*>(1))->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); |
| 62 | if (!sema) { |
| 63 | MOODYCAMEL_THROW(std::bad_alloc()); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | BlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) |
| 68 | : inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create<LightweightSemaphore, ssize_t, int>(0, static_cast<int>(Traits::MAX_SEMA_SPINS)), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>) |
| 69 | { |
| 70 | assert(reinterpret_cast<ConcurrentQueue*>(reinterpret_cast<BlockingConcurrentQueue*>(1)) == &(reinterpret_cast<BlockingConcurrentQueue*>(1))->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); |
| 71 | if (!sema) { |
| 72 | MOODYCAMEL_THROW(std::bad_alloc()); |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | // Disable copying and copy assignment |
| 77 | BlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; |
| 78 | BlockingConcurrentQueue& operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; |
| 79 | |
| 80 | // Moving is supported, but note that it is *not* a thread-safe operation. |
| 81 | // Nobody can use the queue while it's being moved, and the memory effects |
| 82 | // of that move must be propagated to other threads before they can use it. |