SpinLockArray
[folly.git] / folly / ProducerConsumerQueue.h
index de0e3cc0a39892cde2903ad60f560de33b8809d5..670f725436da5be8bcf64b179df7204966e4a3f0 100644 (file)
@@ -38,7 +38,11 @@ template<class T>
 struct ProducerConsumerQueue : private boost::noncopyable {
   typedef T value_type;
 
-  // size must be >= 2
+  // size must be >= 2.
+  //
+  // Also, note that the number of usable slots in the queue at any
+  // given time is actually (size-1), so if you start with an empty queue,
+  // isFull() will return true after size-1 insertions.
   explicit ProducerConsumerQueue(uint32_t size)
     : size_(size)
     , records_(static_cast<T*>(std::malloc(sizeof(T) * size)))
@@ -129,7 +133,7 @@ struct ProducerConsumerQueue : private boost::noncopyable {
   }
 
   bool isEmpty() const {
-   return readIndex_.load(std::memory_order_consume) !=
+   return readIndex_.load(std::memory_order_consume) ==
          writeIndex_.load(std::memory_order_consume);
   }
 
@@ -145,6 +149,20 @@ struct ProducerConsumerQueue : private boost::noncopyable {
     return true;
   }
 
+  // * If called by consumer, then true size may be more (because producer may
+  //   be adding items concurrently).
+  // * If called by producer, then true size may be less (because consumer may
+  //   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);
+    if (ret < 0) {
+      ret += size_;
+    }
+    return ret;
+  }
+
 private:
   const uint32_t size_;
   T* const records_;