Use of std::memory_order_consume in ProducerConsumerQueue

181 views
Skip to first unread message

Alejandro Lucena

unread,
Aug 16, 2015, 2:07:30 PM8/16/15
to Folly: the Facebook Open-source LibrarY
Going through the ProducerConsumerQueue source, I found a couple of instances of std::memory_order_consume loads that read values from writeIndex_ and readIndex_ to test for conditions such as queue fullness,emptiness, and approximate size. However, the contexts in which they're used ( namely, the functions isEmpty(), isFull(), and sizeGuess())  don't seem to require consume semantics. In specific, those functions do a load-consume on  writeIndex_ and readIndex_ , but don't use the corresponding results to form a dependency chain with a prior store-release nor guarantee any sort of data visibility. Since there's no need to preserve ordering or dependency chains in those functions, shouldn't the loads be std::memory_order_relaxed instead?

Consider the definition for isEmpty():

bool isEmpty() const
{
   
return readIndex_.load(std::memory_order_consume) == writeIndex_.load(std::memory_order_consume);
}

I don't see a need for memory_order_consume here, as the results of the loads are only used to check if the two indices are equal. The value of each individual load isn't used to make earlier data visible, making memory_order_consume a bit awkward here. That and the fact that most compilers end up promoting std::memory_order_consume to std::memory_order_acquire ( which introduces unnecessary synchronization in this case ), makes me skeptical about this use of memory_order_consume. I believe std::memory_order_relaxed is the appropriate memory ordering since it accurately conveys the intent of what needs to be done and is even how Boost implements empty() for their implementation of a lock-free SPSC ringbuffer.  

The other two functions I mentioned above - isFull() and sizeGuess() also use memory_order_consume in a manner that doesn't seem to coincide with consume semantics. 

Is there any reason as to why these loads have been tagged consume instead of relaxed? The other use cases of std::memory_order_consume that I've found within Folly are in the ConcurrentSkipList implementations, which do use the result of their load-consumes to enforce an earlier dependency chain.  Is the case for ProducerConsumerQueue any different?

Thanks,

Reply all
Reply to author
Forward
0 new messages