Promote memory_order_consume to memory_order_acquire
authorAlejandro <lucenadeveloper@gmail.com>
Thu, 19 May 2016 16:19:54 +0000 (09:19 -0700)
committerFacebook Github Bot 4 <facebook-github-bot-4-bot@fb.com>
Thu, 19 May 2016 16:23:27 +0000 (09:23 -0700)
Summary:
The current use case of `std::memory_order_consume` in this project was intended to provide the appropriate synchronization in cases where a consumer spins on `while( spsc_queue.empty() ) {} `, and then attempts to use an element of the queue since the loop was broken out of, according to comments [here](https://reviews.facebook.net/D48141). Consume semantics do not provide this guarantee according to the standard since there is no data dependency from the producer that can be carried to the consumer by doing a load-consume from the corresponding functions. What is needed is a load-acquire. Current compilers promote `memory_order_consume` to `memory_order_acquire`. Thus, this example appears to work simply due to the promotion from consume to acquire, but would fail to generate the right synchronization instructions on weaker architectures once `memory_order_consume` is implemented as intended.  Therefore, the `memory_order` should be tightened to `memory_order_acquire` to guarantee visibility to the consumer
Closes https://github.com/facebook/folly/pull/381

Reviewed By: djwatson

Differential Revision: D3173574

Pulled By: nbronson

fbshipit-source-id: b109be2e74f016750a3fe1f848e3fc66e609b9d2

folly/ProducerConsumerQueue.h

index da9b93a4d57efd461185ece5ca7ea75d22e1519a..fd792ca72f57aa2020c033556dfb988ef74bc1d4 100644 (file)
@@ -134,16 +134,16 @@ struct ProducerConsumerQueue {
   }
 
   bool isEmpty() const {
-   return readIndex_.load(std::memory_order_consume) ==
-         writeIndex_.load(std::memory_order_consume);
+    return readIndex_.load(std::memory_order_acquire) ==
+        writeIndex_.load(std::memory_order_acquire);
   }
 
   bool isFull() const {
-    auto nextRecord = writeIndex_.load(std::memory_order_consume) + 1;
+    auto nextRecord = writeIndex_.load(std::memory_order_acquire) + 1;
     if (nextRecord == size_) {
       nextRecord = 0;
     }
-    if (nextRecord != readIndex_.load(std::memory_order_consume)) {
+    if (nextRecord != readIndex_.load(std::memory_order_acquire)) {
       return false;
     }
     // queue is full
@@ -156,8 +156,8 @@ struct ProducerConsumerQueue {
   //   be removing items concurrently).
   // * It is undefined to call this from any other thread.
   size_t sizeGuess() const {
-    int ret = writeIndex_.load(std::memory_order_consume) -
-              readIndex_.load(std::memory_order_consume);
+    int ret = writeIndex_.load(std::memory_order_acquire) -
+        readIndex_.load(std::memory_order_acquire);
     if (ret < 0) {
       ret += size_;
     }