proxygen
|
CRTP specialization of MPMCQueueBase. More...
#include <MPMCQueue.h>
Public Types | |
typedef T | value_type |
using | Slot = detail::SingleElementQueue< T, Atom > |
Public Member Functions | |
MPMCQueueBase (size_t queueCapacity) | |
MPMCQueueBase () noexcept | |
MPMCQueueBase (MPMCQueueBase< Derived< T, Atom, Dynamic >> &&rhs) noexcept | |
MPMCQueueBase< Derived< T, Atom, Dynamic > > const & | operator= (MPMCQueueBase< Derived< T, Atom, Dynamic >> &&rhs) |
~MPMCQueueBase () | |
ssize_t | size () const noexcept |
bool | isEmpty () const noexcept |
Returns true if there are no items available for dequeue. More... | |
bool | isFull () const noexcept |
Returns true if there is currently no empty space to enqueue. More... | |
ssize_t | sizeGuess () const noexcept |
size_t | capacity () const noexcept |
Doesn't change. More... | |
size_t | allocatedCapacity () const noexcept |
Doesn't change for non-dynamic. More... | |
uint64_t | writeCount () const noexcept |
uint64_t | readCount () const noexcept |
template<typename... Args> | |
void | blockingWrite (Args &&...args) noexcept |
template<typename... Args> | |
bool | write (Args &&...args) noexcept |
template<class Clock , typename... Args> | |
bool | tryWriteUntil (const std::chrono::time_point< Clock > &when, Args &&...args) noexcept |
template<typename... Args> | |
bool | writeIfNotFull (Args &&...args) noexcept |
void | blockingRead (T &elem) noexcept |
void | blockingReadWithTicket (uint64_t &ticket, T &elem) noexcept |
Same as blockingRead() but also records the ticket nunmer. More... | |
bool | read (T &elem) noexcept |
bool | readAndGetTicket (uint64_t &ticket, T &elem) noexcept |
Same as read() but also records the ticket nunmer. More... | |
template<class Clock , typename... Args> | |
bool | tryReadUntil (const std::chrono::time_point< Clock > &when, T &elem) noexcept |
bool | readIfNotEmpty (T &elem) noexcept |
Protected Types | |
enum | { kAdaptationFreq = 128, kSlotPadding } |
Protected Member Functions | |
size_t | idx (uint64_t ticket, size_t cap, int stride) noexcept |
uint32_t | turn (uint64_t ticket, size_t cap) noexcept |
bool | tryObtainReadyPushTicket (uint64_t &ticket, Slot *&slots, size_t &cap, int &stride) noexcept |
template<class Clock > | |
bool | tryObtainPromisedPushTicketUntil (uint64_t &ticket, Slot *&slots, size_t &cap, int &stride, const std::chrono::time_point< Clock > &when) noexcept |
bool | tryObtainPromisedPushTicket (uint64_t &ticket, Slot *&slots, size_t &cap, int &stride) noexcept |
bool | tryObtainReadyPopTicket (uint64_t &ticket, Slot *&slots, size_t &cap, int &stride) noexcept |
template<class Clock > | |
bool | tryObtainPromisedPopTicketUntil (uint64_t &ticket, Slot *&slots, size_t &cap, int &stride, const std::chrono::time_point< Clock > &when) noexcept |
bool | tryObtainPromisedPopTicket (uint64_t &ticket, Slot *&slots, size_t &cap, int &stride) noexcept |
template<typename... Args> | |
void | enqueueWithTicketBase (uint64_t ticket, Slot *slots, size_t cap, int stride, Args &&...args) noexcept |
template<typename... Args> | |
void | enqueueWithTicket (uint64_t ticket, Args &&...args) noexcept |
void | dequeueWithTicketBase (uint64_t ticket, Slot *slots, size_t cap, int stride, T &elem) noexcept |
Static Protected Member Functions | |
static int | computeStride (size_t capacity) noexcept |
Protected Attributes | |
size_t | capacity_ |
The maximum number of items in the queue at once. More... | |
union folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >:: { ... } | |
Anonymous union for use when Dynamic = false and true, respectively. More... | |
union folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >:: { ... } | |
Anonymous union for use when Dynamic = false and true, respectively. More... | |
Atom< uint64_t > | dstate_ |
Atom< size_t > | dcapacity_ |
Dynamic capacity. More... | |
Atom< uint64_t > | pushTicket_ |
Enqueuers get tickets from here. More... | |
Atom< uint64_t > | popTicket_ |
Dequeuers get tickets from here. More... | |
Atom< uint32_t > | pushSpinCutoff_ |
Atom< uint32_t > | popSpinCutoff_ |
The adaptive spin cutoff when the queue is empty on dequeue. More... | |
char | pad_ [hardware_destructive_interference_size-sizeof(Atom< uint32_t >)] |
CRTP specialization of MPMCQueueBase.
Definition at line 643 of file MPMCQueue.h.
using folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >::Slot = detail::SingleElementQueue<T, Atom> |
Definition at line 657 of file MPMCQueue.h.
typedef T folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >::value_type |
Definition at line 652 of file MPMCQueue.h.
|
protected |
Definition at line 991 of file MPMCQueue.h.
|
inlineexplicit |
Definition at line 659 of file MPMCQueue.h.
References folly::hardware_destructive_interference_size.
|
inlinenoexcept |
A default-constructed queue is useful because a usable (non-zero capacity) queue can be moved onto it or swapped with it
Definition at line 685 of file MPMCQueue.h.
|
inlinenoexcept |
IMPORTANT: The move constructor is here to make it easier to perform the initialization phase, it is not safe to use when there are any concurrent accesses (this is not checked).
Definition at line 699 of file MPMCQueue.h.
References folly::detail::rhs.
|
inline |
MPMCQueue can only be safely destroyed when there are no pending enqueuers or dequeuers (this is not checked).
Definition at line 738 of file MPMCQueue.h.
|
inlinenoexcept |
Doesn't change for non-dynamic.
Definition at line 804 of file MPMCQueue.h.
|
inlinenoexcept |
Moves a dequeued element onto elem, blocking until an element is available
Definition at line 916 of file MPMCQueue.h.
References ticket, and uint64_t.
|
inlinenoexcept |
Same as blockingRead() but also records the ticket nunmer.
Definition at line 923 of file MPMCQueue.h.
References ticket.
|
inlinenoexcept |
Enqueues a T constructed from args, blocking until space is available. Note that this method signature allows enqueue via move, if args is a T rvalue, via copy, if args is a T lvalue, or via emplacement if args is an initializer list that can be passed to a T constructor.
Definition at line 828 of file MPMCQueue.h.
References testing::Args().
|
inlinenoexcept |
Doesn't change.
Definition at line 799 of file MPMCQueue.h.
|
inlinestaticprotectednoexcept |
We assign tickets in increasing order, but we don't want to access neighboring elements of slots_ because that will lead to false sharing (multiple cores accessing the same cache line even though they aren't accessing the same bytes in that cache line). To avoid this we advance by stride slots per ticket.
We need gcd(capacity, stride) to be 1 so that we will use all of the slots. We ensure this by only considering prime strides, which either have no common divisors with capacity or else have a zero remainder after dividing by capacity. That is sufficient to guarantee correctness, but we also want to actually spread the accesses away from each other to avoid false sharing (consider a stride of 7 with a capacity of 8). To that end we try a few taking care to observe that advancing by -1 is as bad as advancing by 1 when in comes to false sharing.
The simple way to avoid false sharing would be to pad each SingleElementQueue, but since we have capacity_ of them that could waste a lot of space.
Definition at line 1074 of file MPMCQueue.h.
References min, and folly::gen::stride().
|
inlineprotectednoexcept |
Definition at line 1319 of file MPMCQueue.h.
References folly::gen::stride(), and ticket.
|
inlineprotectednoexcept |
Definition at line 1313 of file MPMCQueue.h.
|
inlineprotectednoexcept |
Definition at line 1298 of file MPMCQueue.h.
References testing::Args(), and folly::detail::SingleElementQueue< T, Atom >::enqueue().
|
inlineprotectednoexcept |
Returns the index into slots_ that should be used when enqueuing or dequeuing with the specified ticket
Definition at line 1095 of file MPMCQueue.h.
References folly::gen::stride(), and ticket.
|
inlinenoexcept |
Returns true if there are no items available for dequeue.
Definition at line 778 of file MPMCQueue.h.
References folly::size().
|
inlinenoexcept |
Returns true if there is currently no empty space to enqueue.
Definition at line 783 of file MPMCQueue.h.
References folly::size().
|
inline |
IMPORTANT: The move operator is here to make it easier to perform the initialization phase, it is not safe to use when there are any concurrent accesses (this is not checked).
Definition at line 727 of file MPMCQueue.h.
References folly::gen::move, and folly::detail::rhs.
|
inlinenoexcept |
If an item can be dequeued with no blocking, does so and returns true, otherwise returns false.
Definition at line 931 of file MPMCQueue.h.
References ticket, and uint64_t.
|
inlinenoexcept |
Same as read() but also records the ticket nunmer.
Definition at line 937 of file MPMCQueue.h.
References testing::Args(), folly::gen::stride(), and ticket.
|
inlinenoexcept |
Returns the total number of calls to blockingRead or successful calls to read, including those blockingRead calls that are currently blocking
Definition at line 818 of file MPMCQueue.h.
References testing::Args().
|
inlinenoexcept |
If the queue is not empty, dequeues and returns true, otherwise returns false. If the matching write is still in progress then this method may block waiting for it. If you don't rely on being able to dequeue (such as by counting completed write) then you should prefer read.
Definition at line 975 of file MPMCQueue.h.
References folly::gen::stride(), ticket, and uint64_t.
|
inlinenoexcept |
Returns the number of writes (including threads that are blocked waiting to write) minus the number of reads (including threads that are blocked waiting to read). So effectively, it becomes: elements in queue + pending(calls to write) - pending(calls to read). If nothing is pending, then the method returns the actual number of elements in the queue. The returned value can be negative if there are no writers and the queue is empty, but there is one reader that is blocked waiting to read (in which case, the returned size will be -1).
Definition at line 751 of file MPMCQueue.h.
References uint64_t.
|
inlinenoexcept |
Returns is a guess at size() for contexts that don't need a precise value, such as stats. More specifically, it returns the number of writes minus the number of reads, but after reading the number of writes, more writers could have came before the number of reads was sampled, and this method doesn't protect against such case. The returned value can be negative.
Definition at line 794 of file MPMCQueue.h.
|
inlineprotectednoexcept |
Similar to tryObtainReadyPopTicket, but returns a pop ticket whose corresponding push ticket has already been handed out, rather than returning one whose corresponding push ticket has already been completed. This means that there is a possibility that the caller will block when using the ticket, but it allows the user to rely on the fact that if enqueue has succeeded, tryObtainPromisedPopTicket will return true. The "try" part of this is that we won't have to block waiting for someone to call enqueue, although we might have to block waiting for them to finish executing code inside the MPMCQueue itself.
Definition at line 1272 of file MPMCQueue.h.
References testing::Args(), folly::gen::stride(), and ticket.
|
inlineprotectednoexcept |
Tries until when to obtain a pop ticket for which SingleElementQueue::dequeue won't block. Returns true on success, false on failure. ticket is filled on success AND failure.
Definition at line 1236 of file MPMCQueue.h.
References folly::gen::stride(), ticket, and folly::when().
|
inlineprotectednoexcept |
Tries to obtain a push ticket which can be satisfied if all in-progress pops complete. This function does not block, but blocking may be required when using the returned ticket if some other thread's pop is still in progress (ticket has been granted but pop has not yet completed).
Definition at line 1178 of file MPMCQueue.h.
References int64_t, folly::gen::stride(), and ticket.
|
inlineprotectednoexcept |
Tries until when to obtain a push ticket for which SingleElementQueue::enqueue won't block. Returns true on success, false on failure. ticket is filled on success AND failure.
Definition at line 1147 of file MPMCQueue.h.
References folly::gen::stride(), ticket, and folly::when().
|
inlineprotectednoexcept |
Tries to obtain a pop ticket for which SingleElementQueue::dequeue won't block. Returns true on immediate success, false on immediate failure.
Definition at line 1207 of file MPMCQueue.h.
References folly::gen::stride(), and ticket.
|
inlineprotectednoexcept |
Tries to obtain a push ticket for which SingleElementQueue::enqueue won't block. Returns true on immediate success, false on immediate failure.
Definition at line 1109 of file MPMCQueue.h.
References folly::gen::stride(), and ticket.
|
inlinenoexcept |
Definition at line 952 of file MPMCQueue.h.
References folly::gen::stride(), ticket, uint64_t, and folly::when().
|
inlinenoexcept |
Definition at line 864 of file MPMCQueue.h.
References testing::Args(), folly::gen::stride(), ticket, and uint64_t.
|
inlineprotectednoexcept |
Maps an enqueue or dequeue ticket to the turn should be used at the corresponding SingleElementQueue
Definition at line 1101 of file MPMCQueue.h.
References ticket, and uint32_t.
|
inlinenoexcept |
If an item can be enqueued with no blocking, does so and returns true, otherwise returns false. This method is similar to writeIfNotFull, but if you don't have a specific need for that method you should use this one.
One of the common usages of this method is to enqueue via the move constructor, something like q.write(std::move(x)). If write returns false because the queue is full then x has not actually been consumed, which looks strange. To understand why it is actually okay to use x afterward, remember that std::move is just a typecast that provides an rvalue reference that enables use of a move constructor or operator. std::move doesn't actually move anything. It could more accurately be called std::rvalue_cast or std::move_permission.
Definition at line 847 of file MPMCQueue.h.
References testing::Args(), folly::gen::stride(), ticket, and uint64_t.
|
inlinenoexcept |
Returns the total number of calls to blockingWrite or successful calls to write, including those blockingWrite calls that are currently blocking
Definition at line 811 of file MPMCQueue.h.
|
inlinenoexcept |
If the queue is not full, enqueues and returns true, otherwise returns false. Unlike write this method can be blocked by another thread, specifically a read that has linearized (been assigned a ticket) but not yet completed. If you don't really need this function you should probably use write.
MPMCQueue isn't lock-free, so just because a read operation has linearized (and isFull is false) doesn't mean that space has been made available for another write. In this situation write will return false, but writeIfNotFull will wait for the dequeue to finish. This method is required if you are composing queues and managing your own wakeup, because it guarantees that after every successful write a readIfNotEmpty will succeed.
Definition at line 897 of file MPMCQueue.h.
References folly::gen::stride(), ticket, and uint64_t.
union { ... } |
Anonymous union for use when Dynamic = false and true, respectively.
union { ... } |
Anonymous union for use when Dynamic = false and true, respectively.
|
protected |
The maximum number of items in the queue at once.
Definition at line 1004 of file MPMCQueue.h.
|
protected |
Dynamic capacity.
Definition at line 1034 of file MPMCQueue.h.
Atom<Slot*> folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >::dslots_ |
Current dynamic slots array of dcapacity_ SingleElementQueue-s.
Definition at line 1013 of file MPMCQueue.h.
|
protected |
The following two memebers are used by dynamic MPMCQueue. Ideally they should be in MPMCQueue<T,Atom,true>, but we get better cache locality if they are in the same cache line as dslots_ and dstride_.
Dynamic state. A packed seqlock and ticket offset
Definition at line 1032 of file MPMCQueue.h.
Atom<int> folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >::dstride_ |
Current stride.
Definition at line 1023 of file MPMCQueue.h.
|
protected |
Alignment doesn't prevent false sharing at the end of the struct, so fill out the last cache line
Definition at line 1053 of file MPMCQueue.h.
|
protected |
The adaptive spin cutoff when the queue is empty on dequeue.
Definition at line 1049 of file MPMCQueue.h.
|
protected |
Dequeuers get tickets from here.
Definition at line 1040 of file MPMCQueue.h.
|
protected |
This is how many times we will spin before using FUTEX_WAIT when the queue is full on enqueue, adaptively computed by occasionally spinning for longer and smoothing with an exponential moving average
Definition at line 1046 of file MPMCQueue.h.
|
protected |
Enqueuers get tickets from here.
Definition at line 1037 of file MPMCQueue.h.
Slot* folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >::slots_ |
An array of capacity_ SingleElementQueue-s, each of which holds either 0 or 1 item. We over-allocate by 2 * kSlotPadding and don't touch the slots at either end, to avoid false sharing
Definition at line 1011 of file MPMCQueue.h.
int folly::detail::MPMCQueueBase< Derived< T, Atom, Dynamic > >::stride_ |
The number of slots_ indices that we advance for each ticket, to avoid false sharing. Ideally slots_[i] and slots_[i + stride_] aren't on the same cache line
Definition at line 1021 of file MPMCQueue.h.