Search code examples
c++multithreadingboostboost-thread

C++ clearing queues and thread safety


I have a queue class, the data of which is stored in a vector:

std::vector<boost::shared_ptr<rxImage> > queue;

There is a thread which adds to a queue which is based on this loop:

while(runRxThread){
  this->rxImage();
}

Where rxImage() is defined by:

zmq::message_t img;
imageSocket->recv(&img);

//addToQueue is a push back:
//queue.push_back( boost::shared_ptr<rxImage> (new rxImage(data, imgSize)) );
localQueue->addToQueue((unsigned char*) img.data());

The images are received fine within this thread (I've tested with 10,000 or so and it seems to be fine).

The runRxThread variable is set through some setter functions within the class that the thread function is defined in.

When I run a process in the main thread such as:

startRx(); //start the thread

/*process to stimulate the sending of network data from another program*/

stopRX(); //stop the thread from accessing the queue

queue.clear();

There is a segfault caused by the clear(). I have checked it is definitely this line and not the internal plumbing of the objects, and it definitely is.

It appears to be a thread safety issue but I don't know how to fix it and, more importantly, I don't know why. My understanding is that two threads can write to the same memory, but not at the same time. Surely by setting my runRxThread variables, I ensure that this does not happen.

I would very much like a solution that does not involve mutexes or semaphores - I really don't think they should be necessary for a problem like this.

Thanks!

EDIT: runRXThread is volatile and the thread loop is now:

while(1){
    if(runRxThread == 1){
      this->rxImage();
    }
}

EDIT2: "use a mutex on shared objects"

OK, this is clearly a thread safety issue, I need to make my shared variables threadsafe. But...

1) rxImage(); does not terminate unless there is data being sent

2) The segfault happens within rxImage();

3) If I lock the queue with a mutex, surely the program will hang in rxImage until there is data, because the mutex will not be released

4) There will be no data sent, so the program will hang forever.

Is my understanding here incorrect?

EDIT3:

I have changed rxImage() to be non blocking:

zmq::message_t img;
imageSocket->recv(&img,ZMQ_NOBLOCK);
if((int)img.size() > 0){
    cout<<"in the thread conditional"<<endl;     
    localQueue->addToQueue((unsigned char*) img.data());
    cout<<"leaving thread conditional"<<endl;   
}

The problem earlier was apparently that localQueue was being written to when I was clearing the queue. Now, the queue can only be written in this function when there is data to write to it. I can guarantee that when I call the clear(), there is no data to write, ((int)img.size() > 0) returns false and the queue is not accessed by the thread. Why is there still a segfault? Surely this proves that this thread does not cause the segfault?

Here is a terminal output:

in the thread
pushing back1 of size: 16000000
Added image to queue. queue size: 650
leaving thread conditional

image server stopped
stopping image server
clearing vector
Segmentation fault

It can be seen that the thread is finished with the vector, then the image server is stopped, then the vector is cleared. Precisely in that order with no unpredicted behaviour. But there is still a segfault.


Solution

  • I am the OP, I have fixed the problem.

    The issue is clearly not a thread contention issue, as suggested by other users. This is proven in edit 3 of the original question. The terminal output simulates where a mutex would have been locked and released, and proves that they are necessary in this case - as the threads are synchronised over the network. I accept that this is a very minority case.

    I traced the problem back to the destructor of the image class which is being queued, a variable is deleted and this causes the segfault.