Queue.empty() is false, but the queue size is 0

Viewed 240

I have a std::queue<std::vector<char>> GLOB_DATA_QUEUE; I'm using to tranfer data from one thread to another. I'm having a strange bug when trying to read from the queue. Here's my read code (updated to be completely self-contained):

#include <vector>
#include <queue>
#include <iostream>


// global data pipe object instaciation
// queue for data
std::queue<std::vector<char>> GLOB_DATA_QUEUE;
// global mutex for the thread
std::mutex GLOB_MUTEX;
// global condition variable for producer/consumer
std::condition_variable GLOB_CV;


int main(int argc, char *argv[])
{
      // flow control for main logic loop
    bool keep_running = true;
    
    // this is the main loop we never plan to exit until shutdown
    while(keep_running)
    {
        
        std::cout<<"servicing data queue"<<std::endl;
        // sensor thread gets prioity, so if we can't have the mutex right now, go do something else
        if(GLOB_MUTEX.try_lock())
        {
            std::cout<<"servicing data queue: got lock"<<std::endl;
            std::cout<<"queue size: "<< GLOB_DATA_QUEUE.size() << std::endl;
            
            if(!GLOB_DATA_QUEUE.empty()); // TODO - copy to local variable and release mutex before anything else
            {
                std::cout<<"servicing data queue: pop with queue size: " << GLOB_DATA_QUEUE.size() <<std::endl;
                GLOB_DATA_QUEUE.pop();
            }
            std::cout<<"servicing data queue: unlocking"<<std::endl;
            GLOB_MUTEX.unlock();
                
            // TODO: do something with the data
        }
            
        std::cout<<"finished servicing data queue"<<std::endl;
    
    }
        
        
}

During testing I'm running the above periodically without the provider thread running (so nothing is being input into the queue). What seems to happen is that .empty() keeps returning false, even when the queue is empty. Here's the output I get:

servicing data queue
servicing data queue: got lock
queue size: 0
servicing data queue: pop with queue size: 0
servicing data queue: unlocking
finished servicing data queue
servicing data queue
servicing data queue: got lock
queue size: 4294967295
servicing data queue: pop with queue size: 4294967295
servicing data queue: unlocking
finished servicing data queue

After a few repetitions it segfaults. Clearly the issue is calling .pop() on an empty queue, however what I can't figure out is why this is happening, and how I can fix it. There're no other threads even running at this point, so nothing else is ever touching the queue, and the mutex is in place at both ends anyway. Any ideas or pointers would be much appreciated.

2 Answers

My guess is that the problem is not in the code you show us, but in other part of your code - though it's hard to say since you don't include it.

Your third output line, "queue size: 0" is from another part of your code. So what I think happens, is that after the empty check line, another thread runs and empties the queue without using the mutex. Thus when this thread gets to the next line, the queue is suddenly empty, since the other thread emptied it between those lines.

Having one part of the code protected by a mutex is of no help unless all code that modifies the same variable is protected by the same mutex.

So go check your other code for where "queue size: 0" is output, and you probably find the cause.

As @G.M. noted in comments above, replace

if(!GLOB_DATA_QUEUE.empty());

with

if(!GLOB_DATA_QUEUE.empty())

in addition, add -Wall to your compiler flags, this is something a compiler can and will catch if you say "please tell me if I'm doing something obviously wrong".

Related