From fdbbdb8f25443a74ec7f351abd9b7f13b6b78e13 Mon Sep 17 00:00:00 2001 From: Mike Curtiss Date: Thu, 7 Jun 2012 00:32:14 -0700 Subject: [PATCH] Add sizeGuess() member to ProducerConsumerQueue Summary: This is part 1 of a change to add hysteretic behavior to a blocking queue based on ProducerConsumerQueue. Knowing the size is useful for monitoring and possibly for objects that contain a ProducerConsumerQueue. Test Plan: Added tiny test-case. Tests pass Reviewed By: delong.j@fb.com FB internal diff: D496787 --- folly/ProducerConsumerQueue.h | 14 ++++++++++++++ folly/docs/ProducerConsumerQueue.md | 11 ++++++++--- folly/test/ProducerConsumerQueueTest.cpp | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/folly/ProducerConsumerQueue.h b/folly/ProducerConsumerQueue.h index d5d41aaf..670f7254 100644 --- a/folly/ProducerConsumerQueue.h +++ b/folly/ProducerConsumerQueue.h @@ -149,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_; diff --git a/folly/docs/ProducerConsumerQueue.md b/folly/docs/ProducerConsumerQueue.md index 40ae8cab..22d50f2c 100644 --- a/folly/docs/ProducerConsumerQueue.md +++ b/folly/docs/ProducerConsumerQueue.md @@ -18,12 +18,17 @@ operations: empty). * `isEmpty`: Check if the queue is empty. * `isFull`: Check if the queue is full. + * `sizeGuess`: Returns the number of entries in the queue. Because of the + way we coordinate threads, this guess could be slightly wrong + when called by the producer/consumer thread, and it could be + wildly inaccurate if called from any other threads. Hence, + only call from producer/consumer threads! All of these operations are wait-free. The read operations (including `frontPtr` and `popFront`) and write operations must only be called by the -reader and writer thread, respectively. `isFull` and `isEmpty` may be called by -either thread, but the return values from `read`, `write`, or `frontPtr` are -sufficient for most cases. +reader and writer thread, respectively. `isFull`, `isEmpty`, and `sizeGuess` +may be called by either thread, but the return values from `read`, `write`, or +`frontPtr` are sufficient for most cases. `write` may fail if the queue is full, and `read` may fail if the queue is empty, so in many situations it is important to choose the queue size such that diff --git a/folly/test/ProducerConsumerQueueTest.cpp b/folly/test/ProducerConsumerQueueTest.cpp index 06030481..feaf8a63 100644 --- a/folly/test/ProducerConsumerQueueTest.cpp +++ b/folly/test/ProducerConsumerQueueTest.cpp @@ -281,4 +281,5 @@ TEST(PCQ, EmptyFull) { EXPECT_TRUE(queue.isFull()); // Tricky: full after 2 writes, not 3. EXPECT_FALSE(queue.write(3)); + EXPECT_EQ(queue.sizeGuess(), 2); } -- 2.34.1