0

I am writing usual reader-writer functionality with one main thread that equeues and several threads that dequeues. So, there is a part of the code where I am comparing count of items in my ConcurrentQueue with some integer number, let's call it "maxSize". Despite the fact that .Count returns 1 and maxSize is 10, queue.Count >= maxSize returns true.

I tried to debug with breakpoints, set only one dequeue thread and even pause it. That happened right after main thread enqueued and after several lines of code this comparing returns the result that says 1 >= 10. I am sure the main thread puts only 1 item at this moment, I am sure no Dequeue() was called. Also, I've tried to double-check with locking but sometimes it does not help. I am wondering that there could be some magic that does not allow me to compare values properly in a way I do it, because when I see in a debugger that 1 >= 10 is true, I'm torn apart.


int maxSize = 10;
Timer timer;

ctor(int interval)
{
    queue = new ConcurrentQueue<HttpSessionState>();
    timer = new Timer(TimeSpan.FromSeconds(interval).TotalMilliseconds);
    timer.Elapsed += (sender, args) => PulseIfAvailableForProcessing(true);
}

void Process()
{
    queue.Enqueue(obj);
    // interval here is huge, several minutes
    timer.Start();
    PulseIfAvailableForProcessing(false);
}

bool PulseIfAvailableForProcessing(bool isTimeout)
{
    if (isTimeout)
    {
        ...
    }
    else
    {
        // here 1 >= 10 gives true
        if (queue.Count >= maxSize)
        {
            lock (_dataLock)
            {
                // here in debug queue.Count is still 1, however 1 >= 10 returns false
                if (queue.Count >= maxSize)
                {
                    Pulse();
                }
            }
        }
    }
}

In despair I've added logging and I see that during unit testing the issue is reproducible even inside of a lock statement.

6
  • 1
    When something seems impossible, question all assumptions. If queue.Count >= maxSize then it's safe to say that the values can't be 1 and 10. There are either more items in the queue, or maxSize has changed. The former seems more likely. It would help if we could see more context. There must be more to it than what we can see. Can you post the relevant parts of the class? Commented Apr 22, 2019 at 17:10
  • I can add that between queue.Enqueue(obj); and the first if statement I am starting System.Timers.Timer, it's callback calls the if statements I described. Nothing more. And I tried to put infinite timeout to it - didn't help. I've updated code a little bit in the question. Commented Apr 22, 2019 at 17:25
  • We can't do much more to help you. There are 3 possibilities, in order of likeliness: you have 10 or more elements in the queue, there's a bug in queue.Count (very unlikely on .net framework, plausible if running on .net core since the ConcurrentQueue has been revamped recently), there's a bug in the JIT (very very unlikely). In all three cases, we can't do anything without a repro Commented Apr 22, 2019 at 18:37
  • You can start by saving the count in a variable before doing the comparison (var count = queue.Count; if (count >= maxSize) { ... }, this way, you can inspect what value was used for the comparison, and we can rule out the JIT bug Commented Apr 22, 2019 at 18:38
  • That said, it seems that you have multiple timers (since you start one every time you add an item to the queue). Therefore, it seems reasonable to think that another timer ticks while you're debugging and unblocks the dequeue thread, thus changing the count Commented Apr 22, 2019 at 18:42

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.