c++multithreadinglistqudpsocket

Could std::list be used for a simple lock-free queue?


I am implementing a multi-threaded application in C++11 which uses a thread to poll data from a QUdpSocket (QT5 framework) and another one to process the collected data .

When incoming data is detected by the socket, a ReadyRead() signal is emitted and all datagrams are extracted from a QUdpSocket and copied into a std::list.

void SocketWrapper::QueuePendingDatagrams()
{    
  while (hasPendingDatagrams()) {
    int dataSize = pendingDatagramSize();
    QByteArray tmpQByte = receiveDatagram().data();
    datagramList.push_back(tmpQByte); // see const_data
  }
  emit newDatagrams(&datagramList);
}

In another thread, the consumer is then started and retrieves the first element of the list until the list is empty.

void Worker::ProcessDatagrams(std::list<QByteArray>* pDatagramList)
{
  while (pDatagramList->size() > 0) {
      QByteArray tmpDatagram = pDatagramList->front();
      pDatagramList->pop_front();

      // Process and log the data within the datagram...
}

My question is: As I am always popping the first element and pushing after the last one, is this lock-free approach thread-safe?

I might (and will) receive more data to the socket during the data processing so both threads will end up running at the same time. To me, it seems that the only data race that might occur could overestimate DatagramList->size() but I don't see why it would be a problem. If I continuously receive data, I believe that the whole list will be consumed anyway.


Solution

  • No.

    You're on the right lines, but actually you can't call any container member function from different threads at the same time and expect it to work reliably, because the implementation of those member functions themselves are not [guaranteed to be] thread-safe.

    I don't see why it would be a problem

    Off the record, I'd agree that in the particular case of std::list I wouldn't expect much in the way of practical problems here. Some shops may consider this sufficient reason to go ahead and use this in production. I wouldn't accept it at code review though. The point is that we simply can't* know exactly what the innards do.

    That being said, if you have some special stdlib implementation (or a stdlib implementation with a special flag/switch/option) that does provide this guarantee, then knock yourself out ;) * And at the end of the day you could inspect its code and make that determination for yourself, but honestly that way madness lies!