Search code examples
c++boostlock-free

boost spsc_queue - how to "try pop"?


I have such queue:

    boost::lockfree::spsc_queue<orders_log,  boost::lockfree::capacity<8192>> futOrdersUpdates;

My problem is that sometimes I deque same item several times. I've added some troubleshoot code:

while (bool dequeued = futOrdersUpdates.pop(entryItem) || !endOfTransaction)
{
    if (!dequeued) {
        dequeueLoger.Debug("no items, try again");
        continue;
    } else {
        if (lastRev != 0 && entryItem.replRev == lastRev) {
            dequeueLoger.Debug("duplicate item!");
        }
        lastRev = entryItem.replRev;
    }
            // further processing

The idea is - if endOfTransaction flag is not set, I should "spin", otherwise I can exit if queue is empty.

In logs I found strange things:

  • "no items, try again" - is NEVER appear
  • "duplicate item!" - IS appear.

Expected behavior:

  • "no items, try again" should appear sometimes - when queue is empty but endOfTransaction flag is not set
  • "duplicate item!" should NEVER appear

The question is - if i'm "dequee" spsc_queue correctly? Any bugs in my code?


Solution

  • We can't possibly know why you are getting duplicates, because we have no idea how you fill replRev. It could be a data race right there (I hope you don't do lastRev+1, e.g.).

    1. Note that you likely never get "No items try again" because the loop is skipped entirely, e.g.:

      while (bool dequeued = foo())
      {  
           assert(dequeued); // can never be false here!
      }
      

      will never even enter the loop.

    2. The reason you get duplicates is because you say

      bool dequeued = futOrdersUpdates.pop(entryItem) || !endOfTransaction;
      

      As you know (see your comment) this forces dequeued to be true even if no item was dequeued, because endOfTransaction has not been set yet.

      The value of entryItem is unspecified at that time - but likely just contains the previous value, leading to the "duplicate" message.

    For a nice demo using spsc_queue I recently gave, see this answer: Dynamic generation & safe usage of spsc_queues