cameron314 / cameron314/concurrentqueue

try_enqueue() fail when queue size went down to 0

Open
#292 6 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
12.5k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

Hi, I have the following code snippet that is stuck in the loop of doing try_enqueue(), and hence some remaining threads doing try_dequeue(). (not always repros, had to run it in a bash loop)

  ConcurrentQueue<int> queue(100);

  for (auto i = 0; i < 1000; ++i) {
    threads.push_back(thread([i, &queue, &bitmap, &count]() {
      auto index = i;
      while (!queue.try_enqueue(index)) {
        yield();
      }
    }));

    threads.push_back(thread([&queue, &bitmap, &count]() {
      int index = -1;
      while (!queue.try_dequeue(index)) {
        yield();
      }
    }));
  }

  for (auto& thread : threads) {
    thread.join();
  }

At the time of hang, I could see the queue.size_approx() is 0, but try_enqueue() cannot find a block to use so it fails all the time. My assumption is that we have freelist that holds the blocks, and size 0 implies freelist should hold something.

I feel that I made some wrong assumptions around the queue's internal logic. Would you please correct me :) and help me understand why there's a hang here.

When removing the initial size 100 from the constructor, and guarding the queue size to 100 with my own atomic<int>, the hang seems to go away.

Code compiled with g++ (Ubuntu 9.4.0-1ubuntu1~16.04) 9.4.0

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied C++ reproducer and observing try_enqueue(), try_dequeue(), and size_approx() while the queue reaches size zero. Trace those entry points through the queue's block and freelist handling to identify why enqueue can continue failing. Done means the hang's root cause and expected behavior are established, with a verified correction or documented explanation.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.